问题
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