WPF binding to Listbox selectedItem
First off, you need to implement INotifyPropertyChanged
interface in your view model and raise the PropertyChanged
event in the setter of the Rule
property. Otherwise no control that binds to the SelectedRule
property will "know" when it has been changed.
Then, your XAML
<TextBlock Text="{Binding Path=SelectedRule.Name}" />
is perfectly valid if this TextBlock
is outside the ListBox
's ItemTemplate
and has the same DataContext
as the ListBox
.
Inside the DataTemplate
you're working in the context of a Rule
, that's why you cannot bind to SelectedRule.Name
-- there is no such property on a Rule
.To bind to the original data context (which is your ViewModel) you can write:
<TextBlock Text="{Binding ElementName=lbRules, Path=DataContext.SelectedRule.Name}" />
UPDATE: regarding the SelectedItem property binding, it looks perfectly valid, I tried the same on my machine and it works fine. Here is my full test app:
XAML:
<Window x:Class="TestWpfApplication.ListBoxSelectedItem" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="ListBoxSelectedItem" Height="300" Width="300" xmlns:app="clr-namespace:TestWpfApplication"> <Window.DataContext> <app:ListBoxSelectedItemViewModel/> </Window.DataContext> <ListBox ItemsSource="{Binding Path=Rules}" SelectedItem="{Binding Path=SelectedRule, Mode=TwoWay}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="Name:" /> <TextBox Text="{Binding Name}"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox></Window>
Code behind:
namespace TestWpfApplication{ /// <summary> /// Interaction logic for ListBoxSelectedItem.xaml /// </summary> public partial class ListBoxSelectedItem : Window { public ListBoxSelectedItem() { InitializeComponent(); } } public class Rule { public string Name { get; set; } } public class ListBoxSelectedItemViewModel { public ListBoxSelectedItemViewModel() { Rules = new ObservableCollection<Rule>() { new Rule() { Name = "Rule 1"}, new Rule() { Name = "Rule 2"}, new Rule() { Name = "Rule 3"}, }; } public ObservableCollection<Rule> Rules { get; private set; } private Rule selectedRule; public Rule SelectedRule { get { return selectedRule; } set { selectedRule = value; } } }}
Yocoder is right,
Inside the DataTemplate
, your DataContext
is set to the Rule
its currently handling..
To access the parents DataContext
, you can also consider using a RelativeSource
in your binding:
<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ____Your Parent control here___ }}, Path=DataContext.SelectedRule.Name}" />
More info on RelativeSource
can be found here:
http://msdn.microsoft.com/en-us/library/system.windows.data.relativesource.aspx