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

时间:2015-02-17 09:47:41

标签: wpf mvvm data-binding user-controls dependency-properties

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

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

FilterLists是我要绑定的属性。 Title属性包含一个文本,显示在我的控件中的标签上,这很有效。

我已经设置了一个基本的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>

这是我控制的代码隐藏:

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);
   }
  }
 }
}

启动时,我的控件上会出现两个按钮,但在这种情况下不会出现任何按钮。我已尝试以编程方式设置FilterLists属性(通过向ViewModel传递视图引用,命名我的控件和viewReference.myControl.FilterLists = nll;),这样可行,但我更愿意能够如上所示进行绑定。我错过了什么?

1 个答案:

答案 0 :(得分:1)

除了SetValue之外,您不应该在依赖项属性的CLR包装器中执行任何操作,因为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实例的位置。