我有两个UserControl
DependencyProperties
。我试图理解DataContext
在这里是如何运作的,因为它对我来说似乎不一致,而且可能有些显而易见我错过了。
我的用户控件:
<UserControl x:Class="XYZ.MyControl" xmlns:oxy="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf" ...>
<Grid x:Name="RootGrid">
<oxy:Plot Title="{Binding ChartTitle}" x:Name="PlotxName" IsLegendVisible="False">
.
.
.
<oxy:LineSeries Title="test" ItemsSource="{Binding Items}" DataFieldX="X" DataFieldY="Y" MarkerType="Circle">
<oxy:LineSeries.LabelFormatString>{1}</oxy:LineSeries.LabelFormatString>
<oxy:LineSeries.XAxisKey>X1</oxy:LineSeries.XAxisKey>
</oxy:LineSeries>
</oxy:Plot>
</Grid>
</UserControl>
我的代码背后:
public partial class MyControl: UserControl
{
#region ChartTitle
public string ChartTitle
{
get { return (string)GetValue(ChartTitleProperty); }
set { SetValue(ChartTitleProperty, value); }
}
public static readonly DependencyProperty ChartTitleProperty =
DependencyProperty.Register("ChartTitle", typeof(string), typeof(MFPlot), new PropertyMetadata(""));
#endregion
#region Items
public ObservableCollection<Item> Items
{
get { return (ObservableCollection<Item>)GetValue(ItemsProperty); }
set
{
SetValue(ItemsProperty, value);
}
}
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register("Items", typeof(ObservableCollection<Item>), typeof(MFPlot), new PropertyMetadata(new ObservableCollection<Item>(), ItemsPropertyChanged));
.
.
.
#endregion
public MyControl()
{
SetValue(ItemsProperty, new ObservableCollection<Item>()); //overwrite default collection to avoid using the same one by all MyControls
InitializeComponent();
RootGrid.DataContext = this; //parent element
}
}
我如何使用此控件:
<Page xmlns:local="clr-namespace:XYZ" ...>
<local:MyControl Items="{Binding SubItemsTre}" ChartTitle="TEST TITLE"/>
</Page>
通过这种设置,RootGrid
DataContext(按照最后一行代码设置)应该由它的后代继承,对吧?这适用于Title
的{{1}}属性,它正确显示&#34; TEST TITLE&#34;。但是,它不适用于<oxy:Plot>
的{{1}}属性。它的DataContext仍然与ItemsSource
的父即Page相同,与<oxy:LineSeries>
不同。我浪费了很多时间,发现我必须将MyControl
添加到RootGrid
。这是为什么?为什么一个元素似乎继承了它的父DataContext="{Binding}"
而另一个元素没有?是因为<oxy:Plot>
是DataContext
的孩子,而不是<oxy:LineSeries>
吗?
答案 0 :(得分:1)
DataContext通常由父级继承,而itemscontrol中的项目除外,它通常具有应该作为datacontext呈现的数据模型/实体。
<Page xmlns:local="clr-namespace:XYZ" ...>
<Page.DataContext>
<local:MyControl/> <!-- One way of setting dc... -->
</Page.DataContext>
<local:MyControl Items="{Binding SubItemsTre}" ChartTitle="TEST TITLE"/>
</Page>
另一个选项是在导航到页面时手动设置datacontext,或通过ViewModelLocator设置它。一般来说,你不应该从代码或元素开始设置dc,如果它不是一个非常好的理由。像上面那样设置dc的坏处是,你不能重复使用不同的dc ofc控件。
BTW此代码:
public static readonly DependencyProperty ItemsProperty =DependencyProperty.Register("Items", typeof(ObservableCollection<Item>), typeof(MFPlot), new PropertyMetadata(new ObservableCollection<Item>(), ItemsPropertyChanged));
直接在DC中进行这样的分配实际上会使其成为静态(DO定义中的新ObservableCollection())。
你的ctor也有点可疑:
public MyControl()
{
// Bad pie!!
SetValue(ItemsProperty, new ObservableCollection<Item>()); //overwrite default collection to avoid using the same one by all MyControls
InitializeComponent();
RootGrid.DataContext = this; //parent element
}
public MyControl()
{
InitializeComponent();
Initialize(); // control is not yet loaded...
}
protected void Initialize()
{
Items = new ObservableCollection<Item>();
}
就个人而言,我会将所有属性等移动到一个单独的视图模型中(使用INotifyPropertyChanged而不是使用DO),并将其设置为DataContext。 I found an example here, which is kind of related
希望它有所帮助,
干杯,
了Stian