【问题标题】:UserControl with ObservableCollection as DependencyProperty使用 ObservableCollection 作为 DependencyProperty 的 UserControl
【发布时间】:2013-10-16 15:11:18
【问题描述】:

我想创建我自己的 UserControl(我们称之为“RectAtCoordinates”),它的工作原理与 Canvas 类似,但它应该:

-存储 (x,y) 整数坐标的集合

-在画布上为每个 (x,y) 对绘制矩形(具有任意选择的大小和填充)。 (x,y) 指定矩形的位置。

首先,我创建了简单的坐标类:

class Coordinates : DependencyObject
    {
        public static readonly DependencyProperty XProperty =
            DependencyProperty.Register("X", typeof(int), typeof(Coordinates));

        public static readonly DependencyProperty YProperty =
            DependencyProperty.Register("Y", typeof(int), typeof(Coordinates));

        public int X
        {
            get { return (int)GetValue(XProperty); }
            set { SetValue(XProperty, value); }
        }

        public int Y
        {
            get { return (int)GetValue(YProperty); }
            set { SetValue(YProperty, value); }
        }

        public Coordinates(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
    }

这是我的 RectAtCoordinates UserControl (.xaml):

<UserControl x:Class="RectAtPoint.RectAtCoordinates"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <ItemsControl ItemsSource="{Binding Path=Coos, Mode=OneWay}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Width="300" Height="300" Background="White"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Rectangle Fill="Black" Width="50" Height="50"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Canvas.Left" Value="{Binding Path=X}" />
                <Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>
</UserControl>

最后是RectAtCoordinates 后面的代码:

public partial class RectAtCoordinates : UserControl
    {
        public static readonly DependencyProperty CoosProperty =
            DependencyProperty.Register("Coos", typeof(Coordinates), typeof(RectAtCoordinates));

        private ObservableCollection<Coordinates> Coos
        {
            get { return (ObservableCollection<Coordinates>)GetValue(CoosProperty); }
            set { SetValue(CoosProperty, value); }
        }

        public RectAtCoordinates()
        {
            InitializeComponent();
            Coos = new ObservableCollection<Coordinates>();
        }

        public void AddRectangleAtPosition(int x, int y)
        {
            Coos.Add(new Coordinates(x, y));
        }
    }

但是,在构建我的项目后,它崩溃了。我遇到 CLR20r3 问题。经过进一步检查,我将 RectAtCoordinates 构造函数更改为:

public RectAtCoordinates()
        {
            InitializeComponent();
            try
            {
                Coos = new ObservableCollection<Coordinates>();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
            }
        }

得到了这个错误:

System.ArgumentException: 'System.Collections.ObjectModel.ObservableCollection`1[RectAtPoint.Coordinates]' 不是属性“Coos”的有效值。

在 System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, 对象值、PropertyMetadata 元数据、布尔值 coerceWithDeferredReference,布尔 coerceWithCurrentValue, OperationType operationType, Boolean isInternal)

在 System.Windows.DependencyObject.SetValue(DependencyProperty dp, 对象值)

在 RectAtPoint.RectAtCoordinates.set_Coos(ObservableCollection`1 值)在 c:...\RectAtCoordinates.xaml.cs:line 28

在 RectAtPoint.RectAtCoordinates..ctor() 中 c:...\RectAtCoordinates.xaml.cs:第 36 行

我是考虑 WPF、绑定和依赖属性的新手,所以请考虑到我可能犯了一些基本错误。我发现了许多类似的问题,但我无法完全理解解决方案,因此无法正确应用它们。

【问题讨论】:

标签: c# wpf xaml user-controls observablecollection


【解决方案1】:

我认为你的问题在这里:

 public static readonly DependencyProperty CoosProperty =
            DependencyProperty.Register("Coos", typeof(Coordinates), typeof(RectAtCoordinates));

应该是:

 public static readonly DependencyProperty CoosProperty =
            DependencyProperty.Register("Coos", typeof(ObservableCollection<Coordinates>), typeof(RectAtCoordinates));

试一试:)

=== EDIT === 对于坐标。

我认为你可以这样做:

      public void AddRectangleAtPosition(int x, int y)
            {
                Coos.Add(new Coordinates(x, y));
if (PropertyChanged != null)
                        {
                            PropertyChanged(this, new PropertyChangedEventArgs("Coos"));
                        }
            }

那么你的班级应该有:

public partial class RectAtCoordinates : UserControl, INotifyPropertyChanged

之后,您可以像我通常对 NotifyPropertyChanged 那样拥有一个区域,如下所示:

#region notifypropertychanged region

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged(string propertyName)
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, string propertyName)
{
    if (EqualityComparer<T>.Default.Equals(field, value)) return false;
    field = value;
    OnPropertyChanged(propertyName);
    return true;
}

#endregion

}

试一试:)

【讨论】:

  • 就是这样!你有鹰的眼睛。现在的问题是向集合添加新坐标并没有产生预期的效果(画布仍然是空的)。但是,我认为这是因为我应该支持 Coos 的 CollectionChanged 事件,对吗?
  • 嗯,它不起作用......我已经复制粘贴了你的答案,但没有任何反应。 SetField 方法的任务是什么?它似乎没有在任何地方被调用。即使我添加新坐标,PropertyChanged 似乎也始终为空。最后:我读过这个主题:link“没有理由为 DependencyProperties 实现 INotifyProperty 更改。DependencyProperties 知道它们何时更改。”,但是我不确定我是否正确理解了这个答案的上下文......
【解决方案2】:

我终于找到了解决方案:数据上下文设置不正确。 我必须添加

this.DataContext = this;

到 UserControl 的构造函数或添加:

DataContext="{Binding RelativeSource={RelativeSource Self}}"

到 UserControl 的 xaml 定义。

【讨论】:

  • 将用户控件数据上下文设置为 THIS 或 {​​Binding RelativeSource={RelativeSource Self}} 是完全错误的,因为它会在相对简单的场景中导致绑定对象。始终绑定到用户控件内根元素上的 DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type YOURTYPE}}}"。这也解释了所有的反对意见
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-03
  • 1970-01-01
  • 2012-03-02
  • 2015-02-16
  • 2012-06-06
  • 1970-01-01
  • 2014-03-29
相关资源
最近更新 更多