如何绑定到 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>
并增加了一个属性Name
,NamedListList
继承自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 的实例。
我正在尝试绑定到一个 属性 用户控件,但它似乎不起作用。
<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>
并增加了一个属性Name
,NamedListList
继承自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 的实例。