绑定到UserControl中的DependencyProperty

时间:2012-02-28 18:07:11

标签: wpf wpf-controls

我有一个包含两个不同UserControl的表单 - 一个包含Telerik RadGridView,另一个包含Telerik DataForm。

网格用户控件绑定到ViewModel,该ViewModel包含一个属性,该属性公开网格绑定的Items集合。

当我将表单绑定到该属性时,一切正常 但我需要在窗体控件中访问真正不属于网格控件的viewmodel的其他信息。

所以我想我会在表单usercontrol中添加一个属性,并将其绑定到items集合:

<local:FormControl x:Name="formControl"
    ItemsSource="{Binding items}"
/>

在表单的代码隐藏中,我添加了一个普通的属性:

private object itemsSource;
public object ItemsSource
{
    get { return this.itemsSource; }
    set { this.itemsSource = value; }
}

当然,这不起作用。我有关于必须使用DependencyProperty的错误。我认为这是令人放心的 - 页面实际上是试图绑定到我认为应该的属性。

所以我将它转换为DependencyProperty:

public static DependencyProperty ItemsSourceProperty =
    DependencyProperty.Register("ItemsSource", typeof(object), typeof(FormControl));

public object ItemsSource
{
    get { return GetValue(ItemsSourceProperty); }
    set { SetValue(ItemsSourceProperty, value); }
}

编译并运行没有错误。当然,除了控件的viewmodel没有任何项目。接下来是尝试将ItemsSource属性传递给表单控件的viewmodel:

public FormControl()
{
    InitializeComponent();
    this.DataContext = new FormControlVM(this.ItemsSource);
    ...

这不起作用。构造FormControl()时,ItemsSource为null。所以我在viewmodel中添加了一个setItemsSource()方法,并在ItemsSource属性的set函数中调用它。这也行不通。 xaml显然绑定到属性,但它似乎没有调用属性的set函数。

所以我决定在DependencyProperty上听取ValueChanged事件:

public FormControl()
{
    InitializeComponent();
    this.DataContext = new FormControlVM();
    DependencyPropertyDescriptor prop =
            DependencyPropertyDescriptor.FromProperty(FormControl.ItemsSourceProperty, this.GetType());
    prop.AddValueChanged(this, delegate
    {
        FormControlVM formControlVM = (FormControlVM)this.DataContext;
        formControlVM.setItemsSource(this.ItemsSource);
    });
    ...

它还没有用。似乎永远不会调用ValueChanged委托。

这似乎应该是一件简单的事情,但我无法在网上找到例子,而且我已经尝试了我能想到的每一个组合。

关于我应该如何处理的任何想法?

============关于绑定的其他信息============

威尔要求提供有关绑定的xaml的信息。

如果我把它放在包含用户控件的页面中,将用户控件绑定到页面的viewmodel:

<local:FormControl x:Name="formControl"
        Grid.Column="2"
        DataContext="{Binding}"
        />

然后在用户控件中,将用户控件中的表单绑定到页面的viewmodel的itemsCollection:

<telerik:RadDataForm
        ItemsSource="{Binding itemsCollection}"
        Header="View Item:"
        CommandButtonsVisibility="None"
        AutoGenerateFields="False"
        />

然后一切正常。

但问题是我无法将用户控件绑定到页面的viewmodel。我需要让用户控件的viewmodel公开页面的viewmodel不应该看到的信息。

我不能让用户控件中的表单到达用户控件之外,绑定到页面viewmodel上的属性。这违反了封装,这将使得在不同页面上使用用户控件变得更加复杂,并且严重限制了我将来如何修改控件的内部结构。 (页面不应该知道用户控件中的控件,用户控件中的控件不应该对页面有任何了解。)

当我在页面上包含用户控件时,我想将用户控件绑定到页面的viewmodel的属性,并且我希望用户控件中的任何控件都绑定到用​​户控件或用户的属性control的viewmodel。

我认为这是一个相当常见的事件。但是我无法找到任何可以做到的例子。

1 个答案:

答案 0 :(得分:3)

重述问题:我有一个UserControl,它包含一个嵌入式Telerik DataForm控件。我需要将嵌入的DataForm的ItemsSource属性绑定到我的UserControl所在页面的DataContext的属性。

如果UserControl没有设置DataContext,它将继承页面的DataContext,我可以轻松地将嵌入的DataForm的ItemsSource属性绑定到它的属性,但UserControl有它自己的DataContext。

如果UserControl被编写为仅在此页面上使用,我可以使用RelativeSource绑定将嵌入的DataForm的ItemsSource属性绑定到页面的属性。但是,此UserControl旨在用于许多地方,并且不能对UserControl之外的属性具有静默依赖性。我需要明确依赖。

在UserControl上创建DependencyProperty是正确的方法,但是没有必要尝试在UserControl的viewmodel中复制该属性。

我需要做的是

1:向UserControl添加DependencyProperty:

public QueryableCollectionView ItemsSource
{
    get { return (QueryableCollectionView)GetValue(ItemsSourceProperty); }
    set { SetValue(ItemsSourceProperty, value); }
}
public static readonly DependencyProperty ItemsSourceProperty =
    DependencyProperty.Register("ItemsSource", typeof(QueryableCollectionView), typeof(FormControl));

注意:我不需要实现回调函数。

2:使用RelativeSource绑定将嵌入的DataForm的ItemsProperty绑定到UserControl的这个新的DependencyProperty:

<UserControl
        ...>
    <telerik:RadDataForm
        ItemsSource="{Binding Path=ItemsSource, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
        />
</UserControl>

3:使用正确的类型(DataContext具有类型对象)使页面的viewModel可见:

public partial class MainWindow : Window
{
    public MainWIndow()
    {
        this.InitializeComponent();
        this.DataContext = new MainWindowVM();
    }
    public MainWindowVM viewModel
    { get { return this.DataContext as MainWindowVM; } }
}

4:在页面上,再次使用RelativeSource绑定将UserControl的新ItemsProperty DependencyProperty绑定到页面viewmodel的相应属性:

<Window
        ...>
    <local:FormControl
        ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type telerik:RadPane}},Path=viewModel.items}"
        />
</Window>