无法从ItemsControl模板

时间:2016-12-01 16:35:05

标签: c# wpf xaml data-binding

我试图绑定用户控件属性" MyUserControl.Names"收集物业"名称"主窗口。如果我在ItemsControl模板中执行它,它不起作用,但如果我将控件定义移出ItemsControl模板,它就可以工作。这是xaml:

<Window x:Class="TestItemsControl.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestItemsControl"
        Height="200" Width="200"
        Name="MainControl">
    <StackPanel>
        <ItemsControl ItemsSource="{Binding Groups, ElementName=MainControl}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <!-- This doesn't work -->
                    <StackPanel Background="WhiteSmoke" Height="40" Width="100" Margin="5" HorizontalAlignment="Left">
                        <TextBlock Text="{Binding .}"/>
                        <local:MyUserControl Names="{Binding Names, ElementName=MainControl}"/>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        <!-- This works -->
        <StackPanel Background="WhiteSmoke" Height="40" Width="100" Margin="5" HorizontalAlignment="Left">
            <TextBlock Text="Group3"/>
            <local:MyUserControl Names="{Binding Names, ElementName=MainControl}"/>
        </StackPanel>
    </StackPanel>
</Window>

MainWindow.xaml.cs包含两个依赖项属性:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        SetValue(GroupsProperty, new ObservableCollection<string>());
        SetValue(NamesProperty, new ObservableCollection<string>());

        Groups.Add("Group1");
        Groups.Add("Group2");
        Names.Add("Name1");
        Names.Add("Name2");
    }

    public static readonly DependencyProperty GroupsProperty =
        DependencyProperty.Register("Groups", typeof(ObservableCollection<string>), typeof(MainWindow),
        new PropertyMetadata(null));

    public ObservableCollection<string> Groups
    {
        get { return (ObservableCollection<string>)GetValue(GroupsProperty); }
        set { SetValue(GroupsProperty, value); }
    }

    public static readonly DependencyProperty NamesProperty =
        DependencyProperty.Register("Names", typeof(ObservableCollection<string>), typeof(MainWindow),
        new PropertyMetadata(null));

    public ObservableCollection<string> Names
    {
        get { return (ObservableCollection<string>)GetValue(NamesProperty); }
        set { SetValue(NamesProperty, value); }
    }
}

结果如下:

enter image description here

前两个矩形是ItemsControl生成的。第三个是我在ItemsControl之后手动添加的内容。正如您所看到的,即使代码在两种情况下完全相同,前两个矩形也没有名称,但第三个矩形没有。是否有任何理由不能使用ItemsControl?

修改

以下是MyUserControl.xaml.cs的代码:

public partial class MyUserControl : UserControl
{
    public MyUserControl()
    {
        InitializeComponent();
        SetValue(NamesProperty, new ObservableCollection<string>());
    }

    public static readonly DependencyProperty NamesProperty = DependencyProperty.Register(
        "Names", typeof(ObservableCollection<string>), typeof(MyUserControl),
        new PropertyMetadata(null, NamesPropertyChanged));

    public ObservableCollection<string> Names
    {
        get { return (ObservableCollection<string>)GetValue(NamesProperty); }
        set { SetValue(NamesProperty, value); }
    }

    private static void NamesPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        var control = (MyUserControl)obj;
        var oldCollection = e.OldValue as INotifyCollectionChanged;
        var newCollection = e.NewValue as INotifyCollectionChanged;

        if (oldCollection != null)
            oldCollection.CollectionChanged -= control.NamesCollectionChanged;
        if (newCollection != null)
            newCollection.CollectionChanged += control.NamesCollectionChanged;

        control.UpdateNames();
    }

    private void NamesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        UpdateNames();
    }

    private void UpdateNames()
    {
        NamesPanel.Children.Clear();

        if (Names == null)
            return;

        foreach(var name in Names)
        {
            var textBlock = new TextBlock();
            textBlock.Text = name + ", ";
            NamesPanel.Children.Add(textBlock);
        }
    }
}

MyUserControl.xaml:

<UserControl x:Class="TestItemsControl.MyUserControl"
             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" 
             xmlns:local="clr-namespace:TestItemsControl"
             mc:Ignorable="d" 
             d:DesignHeight="300" 
             d:DesignWidth="300"
             Name="ParentControl">
    <StackPanel Name="NamesPanel" Orientation="Horizontal"/>
</UserControl>

1 个答案:

答案 0 :(得分:2)

SetValue替换UserControl构造函数中的SetCurrentValue。甚至可以不为Names属性分配初始值。

public MyUserControl()
{
    InitializeComponent();
    SetCurrentValue(NamesProperty, new ObservableCollection<string>());
}

SetValue(与SetCurrentValue相对)为Names属性设置所谓的本地值。在第二种情况下分配Binding时,这也被认为是一个本地值,其优先级与构造函数中设置的值相同。

但是,在第一种情况下,Binding是在DataTemplate中设置的,它不会被计为本地值。由于它具有较低的优先级,因此它不会替换初始值。

此处有更多详情:Dependency Property Value Precedence