Cannot bind ItemsSource to ElementName

自闭症网瘾萝莉.ら 提交于 2019-12-12 01:29:04

问题


This is probably a silly question, but I can't make a simple example with ItemsSource work. My XAML:

<Window x:Class="TestDataGrid.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TestDataGrid"
        mc:Ignorable="d" Height="250" Width="300" Name="MyWindow">
    <ListBox ItemsSource="{Binding MyItems, ElementName=MyWindow}" Background="{Binding MyBrush, ElementName=MyWindow}"/>
</Window>

Code:

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    private ObservableCollection<Item> items;

    public MainWindow()
    {
        InitializeComponent();
        items = new ObservableCollection<Item>();
        items.Add(new Item { Key = "Key1", Value = "Value1" });
        items.Add(new Item { Key = "Key2", Value = "Value2" });
        items.Add(new Item { Key = "Key3", Value = "Value3" });
    }

    public ObservableCollection<Item> MyItems
    {
        get { return items; }
    }

    public Brush MyBrush
    {
        get { return Brushes.LightPink; }
    }
}

public class Item
{
    public string Key { get; set; }
    public string Value { get; set; }
}

It works if I set ItemsSource in code, or if I set DataContext=this and then remove ElementName from my binding. But why doesn't it work with ElementName? I can bind the background color like this, but not collection.

I know how to make it work with DataContext, or in code-behind, but I'm interested in why this particular example doesn't work, am I missing something?


回答1:


I know how to make it work with DataContext, or in code-behind, but I'm interested in why this particular example doesn't work, am I missing something?

As pointed out by @Clemens your binding will actually work if you populate the source collection before the InitializeComponent() is called.

The difference between setting a DataContext in code behind and creating an ElementName Binding in XAML is that the latter is already established during the InitializeComponent call. Items that are added later - to a collection that does not implement INotifyCollectionChanged - are ignored.

public MainWindow()
{
    items = new ObservableCollection<Item>();
    items.Add(new Item { Key = "Key1", Value = "Value1" });
    items.Add(new Item { Key = "Key2", Value = "Value2" });
    items.Add(new Item { Key = "Key3", Value = "Value3" });
    InitializeComponent();
}

You could also bind to the parent window using a RelativeSource though, This works:

<ListBox ItemsSource="{Binding MyItems, RelativeSource={RelativeSource AncestorType=Window}}"/>



回答2:


You set your MyItems after initializing your windows and since MyItems in your example doesn't implement a setter and the INotifyPropertyChanged manner, your UI thread is never warn by the change you made on your collection.

Here two solutions you can set up:

SOLUTION 1

Instantiate your Observable collection directly in the get:

public ObservableCollection<Item> MyItems {
        get {
            var _items = new ObservableCollection<Item>();
            _items.Add(new Item { Key = "Key1", Value = "Value1" });
            _items.Add(new Item { Key = "Key2", Value = "Value2" });
            _items.Add(new Item { Key = "Key3", Value = "Value3" });
            return _items;
        }
    }

SOLUTION 2

Use INotifyPropertyChanged interface:

Like that when you set your items, Your UI thread knows there is a change to do in the xaml part

public partial class MainWindow : Window, INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    private ObservableCollection<Item> _items;
    public ObservableCollection<Item> MyItems {
        get { return _items; }
        set {
            _items = value;
            PropertyChanged(this, new PropertyChangedEventArgs(nameof(MyItems)));
        }
    }

    public MainWindow () {
        InitializeComponent();
        MyItems = new ObservableCollection<Item>();
        MyItems.Add(new Item { Key = "Key1", Value = "Value1" });
        MyItems.Add(new Item { Key = "Key2", Value = "Value2" });
        MyItems.Add(new Item { Key = "Key3", Value = "Value3" });
    }

....


来源:https://stackoverflow.com/questions/42006829/cannot-bind-itemssource-to-elementname

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!