我正在尝试在WPF中创建一个包含内容集合的usercontrol,并努力使绑定在子元素上正常工作。我已经看过这个例子了,但我更深层次地嵌套了这个,所以这个解决方案没有帮助:Data Binding in WPF User Controls
这是我的UserControl:
<UserControl x:Class="BindingTest.MyList"
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"
d:DesignHeight="300" d:DesignWidth="300"
x:Name="uc">
<Grid>
<ListView Grid.Row="1" ItemsSource="{Binding Items, ElementName=uc}">
<ListView.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Text}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</UserControl>
代码隐藏:
[ContentProperty("Items")]
public partial class MyList : UserControl {
public MyList() {
InitializeComponent();
}
public ObservableCollection<MyItem> Items { get; set; } = new ObservableCollection<MyItem>();
}
public class MyItem : DependencyObject {
public string Text {
get {
return (string)this.GetValue(TextProperty);
}
set {
this.SetValue(TextProperty, value);
}
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(MyItem), new PropertyMetadata());
}
然后我在应用程序中如何使用它:
<Window x:Class="BindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BindingTest"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Text="{Binding Val1, Mode=TwoWay}" />
<local:MyList Grid.Row="1">
<local:MyItem Text="{Binding Val1}" />
<local:MyItem Text="Two" />
<local:MyItem Text="Three" />
</local:MyList>
<ListView Grid.Row="2">
<ListViewItem Content="{Binding Val1}" />
<ListViewItem Content="Bravo" />
<ListViewItem Content="Charlie" />
</ListView>
</Grid>
</Window>
最后我的窗口:
public partial class MainWindow : Window, INotifyPropertyChanged {
public MainWindow() {
InitializeComponent();
}
string _val1 = "Foo";
public string Val1 {
get { return _val1; }
set {
_val1 = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Val1"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
我遇到的问题是用户控件中的第一个“MyItem”最终显示空白文本,而库存控件中的第一个ListViewItem显示Foo,如你所料。
我理解这是因为在MyList控件中,DataTemplate为集合中的每个项切换DataContext,但无论我在绑定表达式中尝试什么,无论是在窗口还是用户控件中,我都无法得到它正确绑定到窗口上的Val1。
我做错了什么?
答案 0 :(得分:0)
你的MyItem对象的DataContext没有要绑定的Val1值以及绑定中断的原因是正确的。这是您在DataGrids中常见的问题,其中内部项(MyItem)的上下文设置为ItemSource的元素(在您的情况下是ObservableCollection项)。
我总是遇到问题的方法是在DataGrid或Control的资源中包含一个对象,该对象具有对控件的DataContext的引用。这样您就可以将该对象绑定为StaticResource,并且不必更改Control中的XAML。
包含数据上下文的类:
public class BindingProxy : Freezable
{
protected override Freezable CreateInstanceCore() { return new BindingProxy(); }
public static readonly DependencyProperty ContextProperty =
DependencyProperty.Register("Context", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
public object Context
{
get { return (object)GetValue(ContextProperty); }
set { SetValue(ContextProperty, value); }
}
}
然后将BindingProxy的实例添加到MyList的资源中,并将Context属性绑定到MyList的绑定。然后,您可以按名称绑定到BindingProxy作为StaticResource。 Path是资源的Context属性,然后是要绑定到的值的正常路径。
<local:MyList Grid.Row="1">
<local:MyList.Resources>
<local:BindingProxy x:Key="VMProxy" Context="{Binding}"/>
</local:MyList.Resources>
<local:MyItem Text="{Binding Path=Context.Val1, Source={StaticResource VMProxy}}"/>
<local:MyItem Text="Two" />
<local:MyItem Text="Three" />
</local:MyList>
我用你拥有的控件和窗口代码测试它,它就像一个魅力。 我不能完全赞同这个解决方案,因为我在这里找到了它,但对于我的生活,我找不到具有DataGrids解决方案的旧答案。
答案 1 :(得分:0)
实际上,我找到了一种方法来使这项工作正常进行。我没有进行UserControl,而是切换到ItemsControl,并将“MyItem”类更改为子类ContentControl。然后WPF负责为您设置数据上下文。您可以为ItemsControl指定新模板,以避免Grid在列表中显示为自己的项目。
<ItemsControl x:Class="BindingTest.MyList"
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"
d:DesignHeight="300" d:DesignWidth="300"
x:Name="uc">
<ItemsControl.Template>
<ControlTemplate>
<Grid>
<ListView ItemsSource="{Binding Items, ElementName=uc}">
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Label Foreground="Blue" Content="{Binding Path=Text}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.Resources>
</ListView>
</Grid>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
和
public partial class MyList : ItemsControl {
public MyList() {
InitializeComponent();
}
}
public class MyItem : ContentControl {
public string Text {
get {
return (string)this.GetValue(TextProperty);
}
set {
this.SetValue(TextProperty, value);
}
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(MyItem), new PropertyMetadata());
}