任何人都可以帮助以下内容 - 一直在玩这个,但不能让我的生活让它发挥作用。
我有一个包含以下属性的视图模型;
public ObservableCollection<Rule> Rules { get; set; }
public Rule SelectedRule { get; set; }
在我的XAML中我有;
<ListBox x:Name="lbRules" ItemsSource="{Binding Path=Rules}"
SelectedItem="{Binding Path=SelectedRule, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:" />
<TextBox x:Name="ruleName">
<TextBox.Text>
<Binding Path="Name" UpdateSourceTrigger="PropertyChanged" />
</TextBox.Text>
</TextBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
现在ItemsSource工作正常,我得到一个Rule对象列表,其名称显示在lbRules中。
我遇到的麻烦是将SelectedRule属性绑定到lbRules的SelectedItem。我尝试将textblock的text属性绑定到SelectedRule,但它始终为null。
<TextBlock Text="{Binding Path=SelectedRule.Name}" />
我在输出窗口中看到的错误是: BindingExpression路径错误:找不到'SelectedRule'属性。
任何人都可以帮我解决这个问题 - 我不明白为什么它不应该找到SelectedRule属性。
然后我尝试将textblock的text属性更改为bellow,这有效。麻烦的是我想在我的ViewModel中使用SelectedRule。
<TextBlock Text="{Binding ElementName=lbRules, Path=SelectedItem.Name}" />
非常感谢你的帮助。
答案 0 :(得分:25)
首先,您需要在视图模型中实现INotifyPropertyChanged
接口,并在PropertyChanged
属性的setter中引发Rule
事件。否则,绑定到SelectedRule
属性的控件将“知道”何时更改。
然后,你的XAML
<TextBlock Text="{Binding Path=SelectedRule.Name}" />
如果此TextBlock
超出ListBox
的{{1}}并且ItemTemplate
与DataContext
相同,则完全有效。
答案 1 :(得分:11)
在你DataTemplate
的上下文Rule
内,这就是你无法绑定SelectedRule.Name
的原因 - Rule
上没有这样的属性。
要绑定到原始数据上下文(这是您的ViewModel),您可以编写:
<TextBlock Text="{Binding ElementName=lbRules, Path=DataContext.SelectedRule.Name}" />
关于SelectedItem属性绑定的更新:,它看起来完全有效,我在我的机器上尝试了同样的工作,它工作正常。这是我的完整测试应用程序:
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>
代码背后:
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;
}
}
}
}
答案 2 :(得分:3)
Yocoder是对的,
在DataTemplate
内,您的DataContext
设置为其当前处理的Rule
..
要访问父母DataContext
,您还可以考虑在绑定中使用RelativeSource
:
<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ____Your Parent control here___ }}, Path=DataContext.SelectedRule.Name}" />
RelativeSource
的更多信息可在此处找到:
http://msdn.microsoft.com/en-us/library/system.windows.data.relativesource.aspx
答案 3 :(得分:0)
对我来说,我通常一起使用DataContext
来绑定两个深度属性,例如这个问题。
<TextBlock DataContext="{Binding SelectedRule}" Text="{Binding Name}" />
或者,我更喜欢使用ElementName
,因为它只能使用视图控件实现绑定。
<TextBlock DataContext="{Binding ElementName=lbRules, Path=SelectedItem}" Text="{Binding Name}" />
答案 4 :(得分:-7)
因为您将itemsource设置为您的集合,所以您的文本框与该集合中的每个单独项目相关联。如果您尝试执行具有2个列表框的主 - 详细信息表单,则所选项属性在此方案中很有用。您可以将第二个列表框的itemsource绑定到子规则集合。换句话说,所选项目会警告您的源已更改的外部控件,内部控件(数据模板中的那些已经知道更改。
并在大多数情况下回答您的问题是设置itemsource与设置控件的datacontext相同。