为什么绑定到用户控件上的DepenencyProperty会使用用户控件的数据上下文?

时间:2013-02-07 20:12:31

标签: c# .net wpf binding

假设我在MainWindow.xaml中有一个WPF应用程序(exe):

<Grid>
    <extraControls:MyMVVMUserControl MyDependencyProperty="{Binding Something}"/>
    <extraControls:MyUserControl MyDependencyProperty="{Binding Something}" />
</Grid>

和我的MainWindow.xaml.cs看起来像这样:

public MainWindow()
{
    DataContext = new MainWindowVM();
    InitializeComponent();
}

我的MainWindowVM.cs有Something的属性设置,通知属性已更改。

用户控件是在一个单独的dll中创建的。正如您可能猜到的那样,MyMVVMUserControl将DataContext设置为视图模型。

public MyMVVMUserControl()
{
    DataContext = new MyMVVMUserControlVM();
    InitializeComponent();
}

MyUserControl后面的代码中没有设置DataContext。

有趣的是,他们都MyDependencyProperty设置完全相同。

但是MVVM版本不起作用。

经过深入研究后,我发现 MainWindow.xaml 中的{Binding Something}正在使用MyMVVMUserControl的View Model设置作为DataContext(而不是MainWindow中设置的DataContext)。 cs(设置为MainWindowVM))。

我的问题是为什么?

为什么WPF会查看用户控件并将其DataContext用于实际应用程序中的绑定?

(注意:我知道我可以通过在绑定中设置源代码来解决这个问题,但我希望其他人能够使用我的用户控件。但是对于这个问题,我现在有一个内置的“gotcha”for任何我想使用我的用户控件的人。)

2 个答案:

答案 0 :(得分:2)

我想我理解你的问题,我将给出一个适合我的解决方案(之前我遇到过这个问题)。我们认为你在后面的代码中为你DataContext设置了MyMVVMUserControl,然后它接受了绑定。

我找到的解决方案是将datacontext设置在代码后面,而不是用户控件。为UserControl的子项设置datacontext。例如,supose这是您的UserControl的Xaml:

<UserControl ... x:Name="userControl">
    <Grid x:Name="rootContainer">
         ...
    </Grid>
</UserControl>

然后在后面的代码中设置rootContainer的数据上下文,这样所有可视子项都可以访问控制数据上下文,用户控件datacontext也是空的。

...
rootContainer.DataContext = new UserControlViewModel();
...

希望这可以帮助您解决问题......

答案 1 :(得分:1)

你真的不应该在DataContext内设置UserControl的{​​{1}}。通过这样做,您可以阻止任何其他UserControl传递给DataContext,这会破坏WPF拥有单独的UI和数据层的最大优势之一。

如果UserControl未设置为其他任何内容,则WPF对象仅从父对象继承其DataContext。在创建DataContext时,您将MyMVVMUserControl设置为新的DataContext,这会阻止MyMVVMUserControlVM继承DataContext

正常情况是MainWindowMVVMUserControl设置为DataContext,因为您在UserControl的构造函数中明确设置了它。

这是按设计的。 WPF / MVVM中的UI对象仅仅是数据层的可视化表示,因此设置数据层然后尝试将属性绑定到不在数据层上的内容是没有多大意义的。

例如,请使用以下代码行:

MyMVVMUserControlVM

这会将 <UserControl DataContext="{Binding ClassA}" Content="{Binding Name}" /> 属性绑定到Content,即UserControl.DataContext.Name。如果这会导致绑定到ClassA.Name,那将没有多大意义,因为绑定应该引用当前对象的UserControl.Parent.DataContext.Name,而不是父对象的DataContext

所以我唯一一次从DataContext本身设置DataContext的{​​{1}}就是UserControl是它自己的独立对象与来自应用程序其余部分的数据进行交互。到目前为止一直没有:)

通常我的UserControl几乎总是两件事之一:

  • UserControl(或UserControls)的直观表示,例如ViewModel的{​​{1}},在这种情况下,我将Model传递给CustomerUserControl他们在使用时需要{1}}

    例如,

    CustomerViewModel

    DataContext
  • 或者是一个自持的UI对象,它通过自定义<local:CustomerUserControl DataContext="{Binding SelectedCustomer}" /> 接收所需的任何外部数据,并在控件后面的代码中执行任何其他逻辑,例如<DataTemplate DataType="{x:Type local:CustomerModel}"> <local:CustomerUserControl /> </DataTemplate> 控件具有DependencyProperties依赖项属性或DatePicker具有SelectedDateCalculatorUserControl

    的依赖项属性的属性
    Equation

在您的情况下,听起来您应该使用第一种情况,并且应该将Value传递到包含所需数据的<local:DatePickerUserControl SelectedDate="{Binding SomeDate}" /> <local:CalculatorUserControl Equation="{Binding SomeString}" Value="{Binding SomeDouble}" />

ViewModel

UserControl