Reputation: 12476
I learn bindings in WPF via book. I have wrote such code:
using System;
namespace WpfBinding {
enum SomeColors {
Red,
Green,
Blue,
Gray
}
}
and
using System;
namespace WpfBinding {
class TestItem {
SomeColors color;
public TestItem(SomeColors color) {
Color = color;
}
internal SomeColors Color {
get { return color; }
set { color = value; }
}
public override string ToString() {
return Color.ToString();
}
}
}
XAML of my Window:
<Window x:Class="WpfBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListBox x:Name="listBox" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Margin="5"/>
<ComboBox x:Name="comboBox" HorizontalAlignment="Stretch"
VerticalAlignment="Top" Margin="5" Grid.Column="1"/>
</Grid>
</Window>
I have tried create binding through code:
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfBinding {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
// Data for listbox
TestItem[] items = new TestItem[] {
new TestItem(SomeColors.Red),
new TestItem(SomeColors.Green),
new TestItem(SomeColors.Green),
new TestItem(SomeColors.Red),
new TestItem(SomeColors.Blue),
new TestItem(SomeColors.Red),
};
// Create ObservableCollection item
ObservableCollection<TestItem> collection = new ObservableCollection<TestItem>(items);
listBox.ItemsSource = collection;// set data for listbox
comboBox.ItemsSource = Enum.GetValues(typeof(SomeColors)); // Get items from my enum
// Create bindings
Binding bind = new Binding();
bind.Source = listBox;
bind.Path = new PropertyPath("SelectedItem.Color");
bind.Mode = BindingMode.TwoWay;
comboBox.SetBinding(ComboBox.SelectedItemProperty, bind);
}
}
}
But my binding ain't working. Why?
Screen:
Upvotes: 0
Views: 2283
Reputation: 12476
Thanks all. I have edit my code:
using System;
using System.ComponentModel;
namespace WpfBinding {
public class TestItem : INotifyPropertyChanged{
SomeColors color;
public TestItem(SomeColors color) {
Color = color;
}
public SomeColors Color {
get { return color; }
set { color = value;
OnPropertyChanged("Color");
}
}
public override string ToString() {
return Color.ToString();
}
void OnPropertyChanged(String name) {
PropertyChangedEventHandler temp = PropertyChanged;
if (null != temp) {
temp(this, new PropertyChangedEventArgs(name));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
and
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfBinding {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
// Data for listbox
TestItem[] items = new TestItem[] {
new TestItem(SomeColors.Red),
new TestItem(SomeColors.Green),
new TestItem(SomeColors.Green),
new TestItem(SomeColors.Red),
new TestItem(SomeColors.Blue),
new TestItem(SomeColors.Red),
};
// Create ObservableCollection item
ObservableCollection<TestItem> collection = new ObservableCollection<TestItem>(items);
listBox.ItemsSource = collection;// set data for listbox
ObservableCollection<SomeColors> collection2 = new
ObservableCollection<SomeColors>(Enum.GetValues(typeof(SomeColors)).Cast<SomeColors>());
comboBox.ItemsSource = collection2; // Get items from my enum
// Create bindings
Binding bind = new Binding();
bind.Source = listBox;
bind.Path = new PropertyPath("SelectedItem.Color");
bind.Mode = BindingMode.TwoWay;
comboBox.SetBinding(ComboBox.SelectedItemProperty, bind);
}
}
}
Look Screen, please:
Upvotes: 1
Reputation: 81243
Here is the error -
System.Windows.Data Error: 40 : BindingExpression path error: 'Color' property
not found on 'object' ''TestItem' (HashCode=13974362)'.
BindingExpression:Path=SelectedItem.Color; DataItem='ListBox' (Name='listBox');
target element is 'ComboBox' (Name='comboBox'); target property is 'SelectedItem'
(type 'Object')
You need to make the property Color
public
instead of internal
.
From MSDN here -
The properties you use as binding source properties for a binding must be public properties of your class. Explicitly defined interface properties cannot be accessed for binding purposes, nor can protected, private, internal, or virtual properties that have no base implementation.
Upvotes: 2
Reputation: 19842
I think the problem is that your classes are not implementing INotifyPropertyChanged
.
In order for the bindings to know when a property has changed it's value, you have to send it notification, and you do that with INotifyPropertyChanged
.
UPDATE
So your listbox is bound to an ObservableCollection
which does provide change notifiations, but only to the list box and only if you add or remove items from the collections.
You might also want to enable WPF Binding trace information in visual studio (http://msdn.microsoft.com/en-us/library/dd409960%28v=vs.100%29.aspx) that might help you figure out what is going on too.
The last thing I noticed is that the Color property of your TestItem
class is marked as internal
. WPF won't have access to that property unless it's public
.
Upvotes: 2
Reputation: 5711
It's always useful to watch the Output window of Visual Studio when debugging! Had you looked there, you'd have seen this:
System.Windows.Data Error: 40 : BindingExpression path error: 'Color' property not found on 'object' ''TestItem' (HashCode=20856310)'. BindingExpression:Path=SelectedItem.Color; DataItem='ListBox' (Name='listBox'); target element is 'ComboBox' (Name='comboBox'); target property is 'SelectedItem' (type 'Object')
Exactly, binding can be done with public properties only, so
internal SomeColors Color
should be
public SomeColors Color
Upvotes: 2