简体   繁体   English

WPF DataContext继承混乱

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM