wpf - 绑定(bind)到 UserControl 中的 DependencyProperty

标签 wpf wpf-controls

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

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

当我将表单绑定(bind)到该属性时,一切正常。
但我需要访问表单控件中实际上不属于网格控件的 View 模型的其他信息。

所以我想我应该向表单用户控件添加一个属性,并将其绑定(bind)到项目集合:

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

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

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

当然,这不起作用。我收到有关必须使用 DependencyProperty 的错误。我认为这令人放心 - 该页面实际上正在尝试绑定(bind)到我认为应该的属性。

所以我将其转换为 DependencyProperty:

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

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

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

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

这没有用。构造 FormControl() 时 ItemsSource 为 null。因此,我向 View 模型添加了 setItemsSource() 方法,并在 ItemsSource 属性的 set 函数中调用它。这也行不通。 xaml 显然绑定(bind)到该属性,但它似乎没有调用属性的 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 委托(delegate)似乎从未被调用。

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

关于我应该如何处理这个问题有什么想法吗?

============ 有关绑定(bind)的附加信息 ============

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

如果我将其放在包含用户控件的页面中,则将用户控件绑定(bind)到页面的 View 模型:

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

然后在用户控件中,将用户控件中的表单绑定(bind)到页面 View 模型的 itemsCollection:

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

然后一切正常。

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

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

当我在页面上包含用户控件时,我希望将用户控件绑定(bind)到页面 View 模型的属性,并且希望用户控件中的任何控件绑定(bind)到用户控件或用户的属性控件的 View 模型。

我认为这是一个相当普遍的现象。但我无法找到任何如何完成此操作的示例。

最佳答案

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

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

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

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

我需要做的是

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 绑定(bind)将嵌入式DataForm 的ItemsProperty 绑定(bind)到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:在页面上,再次使用RelativeSource 绑定(bind),将 UserControl 的新 ItemsProperty DependencyProperty 绑定(bind)到页面 View 模型的相应属性:

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

关于wpf - 绑定(bind)到 UserControl 中的 DependencyProperty,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9487352/

相关文章:

wpf - ContextMenu 不会根据 Binding 更改 MenuItem.Visibility 属性

c# - 创建自定义全尺寸日历控件

c# - 在数据重新加载时保存 WPF TreeView 状态

c# - 如何将数据表绑定(bind)到 wpf 可编辑组合框 : selectedItem showing System. Data.DataRowView

.net - Winforms\WPF - 如何创建类似图形的流程图

c# - 为什么我的 WPF 托管 WinForm 是空白的?

.net - WPF 中的 StackPanel 与 DataGrid 与 DockPanel

.net - 在覆盖 WPF 中制作透明孔

带有圆角的 WPF 超链接图像

c# - WPF 单击 ListBoxItem 内的控件不选择 ListBoxItem