如何绑定到 WPF 中 UserControl 的 属性?

How to bind to a property of a UserControl in WPF?

我正在尝试绑定到一个 属性 用户控件,但它似乎不起作用。

<Controls:BasicFilter Title="Some title" FilterLists="{Binding LocationFilterLists}"/>

FilterLists 是我要绑定的 属性。标题 属性 包含显示在我控制范围内的标签上的文本,效果很好。

我已经设置了一个基本的 ViewModel,它试图设置 LocationFilterLists。因为它绑定到我的控件的 FilterLists 属性,所以我希望这会将该值设置为 属性,但那没有发生。这是我的 ViewModel 的代码:

public class MainViewModel : DependencyObject
{
 public NamedListList LocationFilterLists
 {
  get { return (NamedListList)GetValue(LocationFilterListsProperty); }
  set { SetValue(LocationFilterListsProperty, value); }
 }
 public static readonly DependencyProperty LocationFilterListsProperty =
     DependencyProperty.Register("LocationFilterLists", typeof(NamedListList), typeof(MainViewModel), new PropertyMetadata(null));

 public MainViewModel()
 {
 }

 internal void Refresh()
 {
  NamedListList nll = new NamedListList();
  NamedList nl1 = new NamedList();
  nl1.Name = "filter1";
  NamedList nl2 = new NamedList();
  nl2.Name = "filter2";
  nll.Add(nl1);
  nll.Add(nl2);
  LocationFilterLists = nll;
 }
}

NamedList继承自List<object>并增加了一个属性NameNamedListList继承自List<NamedList>。我已将视图设置为在 DataContext 设置为此 ViewModel 后立即调用 Refresh 方法。

这是我的控件 XAML:

<UserControl x:Class="Plin.CommonDisplayObjects.Controls.BasicFilter"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d">
 <Grid Background="Gray">
  <DockPanel x:Name="dockPanel" Margin="3">
   <Label Content="{Binding Title}" DockPanel.Dock="Top" Margin="0" Padding="5,3,5,3"/>
  </DockPanel>
 </Grid>
</UserControl>

这是我控制的 code-behind:

public partial class BasicFilter : UserControl
{
 #region Dependency Properties
 public string Title
 {
  get { return (string)GetValue(TitleProperty); }
  set { SetValue(TitleProperty, value); }
 }
 public static readonly DependencyProperty TitleProperty =
     DependencyProperty.Register("Title", typeof(string), typeof(BasicFilter), new PropertyMetadata(""));

 public NamedListList FilterLists
 {
  get { return (NamedListList)GetValue(FilterListsProperty); }
  set
  {
   SetValue(FilterListsProperty, value);
   RegenerateFilter(); // Every time property is set, new buttons should be generated.
  }
 }
 public static readonly DependencyProperty FilterListsProperty =
     DependencyProperty.Register("FilterLists", typeof(NamedListList), typeof(BasicFilter), new PropertyMetadata(null));
 #endregion

 public BasicFilter()
 {
  InitializeComponent();
  this.DataContext = this;
 }

 private void RegenerateFilter()
 {
  dockPanel.Children.Clear();
  if (FilterLists != null)
  {
   foreach (NamedList nl in FilterLists)
   {
    Button b = new Button();
    b.Content = "Some generic content " + nl.Name;
    // set other properties on Button
    dockPanel.Children.Add(b);
   }
  }
 }
}

启动时,我的控件上应该会出现两个按钮,但在本例中会出现 none。我已经尝试以编程方式设置 FilterLists 属性(通过将视图引用传递给 ViewModel,命名我的控件和 viewReference.myControl.FilterLists = nll;)并且这有效,但我更希望能够绑定为如上所示。我错过了什么?

除了在依赖项 属性 的 CLR 包装器中 SetValue 之外,您不应该做任何事情,因为包装器可能会被 WPF 绕过。有关详细信息,请参阅 MSDN 上的 XAML Loading and Dependency Properties 文章。

而不是在 setter 中调用 RegenerateFilter(),您必须注册一个具有依赖性 属性 元数据的 PropertyChangedCallback:

public NamedListList FilterLists
{
    get { return (NamedListList)GetValue(FilterListsProperty); }
    set { SetValue(FilterListsProperty, value); }
}

public static readonly DependencyProperty FilterListsProperty =
    DependencyProperty.Register(
        "FilterLists", typeof(NamedListList), typeof(BasicFilter),
        new PropertyMetadata(null, FilterListsPropertyChanged));

private static void FilterListsPropertyChanged(
    DependencyObject o, DependencyPropertyChangedEventArgs e)
{
    ((BasicFilter)o).RegenerateFilter();
}

也就是说,您的视图模型不应从 DependencyObject 派生并声明依赖属性。相反,它应该实现 INotifyPropertyChanged 接口,并在必须通知集合更改时使用 ObservableCollections。


编辑:由于 BasicFilter 构造函数中的语句 this.DataContext = this;,UserControl 的 DataContext 设置为其自身,而不是任何视图模型实例。因此,绑定基础结构在 UserControl 中搜索绑定源 属性 LocationFilterLists,当然不存在。

从 BasicFilter 构造函数中删除该行,并让 UserControl 从其父控件(自动工作)继承其 DataContext。这假设例如 DataContext MainWindow 在某处设置为 MainViewModel 的实例。