[英]WPF DataContext inheritance confusion
I have UserControl
with two DependencyProperties
. 我有两个
DependencyProperties
UserControl
。 I'm trying to understand how DataContext
works here, because it seems inconsistent for me and it's probably somethin obvious that I'm missing. 我试图了解
DataContext
在这里是如何工作的,因为它对我来说似乎前后不一致,而且很明显我很想念。
My user control: 我的用户控件:
<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>
My code behind: 我后面的代码:
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
}
}
How I use this control: 我如何使用此控件:
<Page xmlns:local="clr-namespace:XYZ" ...>
<local:MyControl Items="{Binding SubItemsTre}" ChartTitle="TEST TITLE"/>
</Page>
With this setup, RootGrid
DataContext (set as per last line of code behind) should be inherited by it's descendants, right? 使用此设置,
RootGrid
DataContext(根据后面的代码的最后一行设置)应该由其后代继承,对吗? This works for Title
property of <oxy:Plot>
, it displays correctly "TEST TITLE". 这适用于
<oxy:Plot>
Title
属性,它正确显示“ TEST TITLE”。 However, it doesn't work for ItemsSource
property of <oxy:LineSeries>
. 但是,它不适用于
<oxy:LineSeries>
ItemsSource
属性。 It's DataContext is still the same as MyControl
's parent ie Page, not the same as RootGrid
. 它的DataContext仍然与
MyControl
的父项(即Page)相同,而不与RootGrid
相同。 I have wasted a lot of time on this and found out that I have to add DataContext="{Binding}"
to <oxy:Plot>
. 我在此上浪费了很多时间,发现必须将
DataContext="{Binding}"
到<oxy:Plot>
。 Why is that? 这是为什么? Why one element seems to inherit it's parent
DataContext
while the other doesn't? 为什么一个元素似乎继承其父
DataContext
而另一个元素却不继承? Is it because <oxy:LineSeries>
is child of <oxy:Plot>
, not RootGrid
? 是否因为
<oxy:LineSeries>
是<oxy:Plot>
而不是RootGrid
?
It's true that DataContext generally is inherhitted by the parent, with the exception beeing items in an itemscontrol, which typically has the datamodel/entity it should present as datacontext. 的确,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>
Another option is to set the datacontext manually when navigating to the page, or setting it through a ViewModelLocator. 另一种选择是在导航到页面时手动设置数据上下文,或通过ViewModelLocator进行设置。 Generally your should not start setting dc from the code, or on elements, if it isn't a really really good reason for it.
通常,如果不是真的非常好的理由,则不应从代码或元素上开始设置dc。 The bad thing about setting dc like above, is that you cannnot reuse your control with a different dc ofc.
像上面那样设置dc的坏处是,您无法使用其他dc ofc重用控件。
BTW this code: 顺便说一句这段代码:
public static readonly DependencyProperty ItemsProperty =DependencyProperty.Register("Items", typeof(ObservableCollection<Item>), typeof(MFPlot), new PropertyMetadata(new ObservableCollection<Item>(), ItemsPropertyChanged));
Allocating like this directly in the DC will actually make it static (new ObservableCollection() in the DO definition). 像这样直接在DC中分配实际上将使其静态(DO定义中为new ObservableCollection())。
Your ctor is a bit fishy too: 您的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>();
}
Personally, I would have moved all properties etc into a separate viewmodel(using INotifyPropertyChanged rather than beeing a DO), and set that as DataContext. 就个人而言,我将所有属性等移至单独的视图模型中(使用INotifyPropertyChanged而不是使用DO),并将其设置为DataContext。 I found an example here, which is kind of related
我在这里找到一个例子,这与
Hope it helps, 希望能帮助到你,
Cheers, 干杯,
Stian 了Stian
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.