WPF DataContext继承混乱

时间:2014-08-24 07:56:32

标签: c# wpf inheritance

我有两个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>吗?

1 个答案:

答案 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