【问题标题】:Binding to DependencyProperty in UserControl绑定到 UserControl 中的 DependencyProperty
【发布时间】:2012-02-28 18:07:10
【问题描述】:

我有一个包含两个不同用户控件的表单 - 一个包含 Telerik RadGridView,另一个包含 Telerik DataForm。

网格用户控件绑定到一个 ViewModel,该 ViewModel 包含一个属性,该属性公开了网格绑定到的 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); }
}

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

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

这没有用。构造 FormControl() 时,ItemsSource 为空。所以我在视图模型中添加了一个 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 委托似乎永远不会被调用。

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

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

============ 关于绑定的附加信息 ============

Will 要求提供有关执行绑定的 xaml 的信息。

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

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

然后在用户控件中this,将用户控件中的表单绑定到页面视图模型的itemsCollection:

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

然后一切正常。

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

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

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

我认为这是一个相当普遍的事件。但我无法找到任何关于如何完成的示例。

【问题讨论】:

  • 是的。虽然很高兴知道你是如何到达兔子洞的底部的,但我不知道你为什么会掉下去。您试图在 FormControl 内部 完成什么需要您向其中添加 ItemsSource 属性,以及您试图在 UserControl 内部对该对象做什么?
  • FormControl 包含一个 Form,并且该 Form 具有 ItemsSource 属性。我想提升该属性,以便当我将 FormControl 放在页面上时,我绑定到 FormControl 上的属性,而不是进入控件并绑定到其中的某些内容。 (得墨忒耳法则)。
  • 您正在尝试将事物绑定在一起,但绑定不起作用但我认为没有人能说出来,因为您添加了除 xaml 之外的所有内容,但您希望绑定工作的绑定不是' t.

标签: wpf wpf-controls


【解决方案1】:

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

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

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

在 UserControl 上创建 DependencyProperty 是正确的方法,但无需尝试在 UserControl 的视图模型中复制该属性。

我需要做的是

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:使页面的 viewModel 可见,具有适当的类型(DataContext 具有类型对象):

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

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

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

【讨论】:

  • +1 for RelativeSource={RelativeSource AncestorType={x:Type UserControl}}
猜你喜欢
  • 2012-06-06
  • 2013-06-03
  • 1970-01-01
  • 2014-06-22
  • 2016-05-13
  • 1970-01-01
  • 2013-01-20
  • 2014-12-22
相关资源
最近更新 更多