wpf 向上绑定:绑定到嵌套 uiElement 内的视图模型 属性
wpf binding upwards: bind to view model property inside nested uiElement
我有一个带有视图模型和一些嵌套 UI 元素的 WPF 项目。这是XAML的(相关部分):
<UserControl> // DataContext is MyVM (set programmatically)
<TreeView ItemsSource="{Binding Trees}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Subtrees}">
<StackPanel>
<ListView ItemsSource="{Binding Contents}"
SelectedValue="{Binding SelectedContent}" // won't work: Tree has no such property
SelectionMode="Single"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</UserControl>
这里是 ViewModel 的代码 class:
public class MyVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public IEnumerable<Tree> Trees { get; set; }
private object _selectedContent;
public string SelectedContent
{
get => _selectedContent;
set
{
_selectedContent = value;
OnPropertyChanged();
}
}
}
这里是 class Tree
的代码:
public class Tree
{
public IEnumerable<Tree> Subtrees { get; set; }
public IEnumerable<string> Contents { get; set; }
}
我想为所有 ListViews
在全局范围内只允许一个选择。就像here一样,我想将所有ListViews
绑定到视图模型MyVM
.
中的属性SelectedContent
问题是 ListView
的数据上下文是 Tree
,而不是来自顶级用户控件的 MyVM
。 (它应该是 Tree
,因为我们想显示 Contents
。)我知道我可以使用 SelectedValuePath
向下绑定,但是我如何向上绑定才能绑定 [=25] =] 到 MyVM
属性 SelectedContent
?
我试过SelectedValue="{Binding RelativeSource={RelativeSource AncestorType ={x:Type UserControl}}, Path=SelectedContent}"
,但是没有用。
尝试使用
SelectedValue="{Binding RelativeSource={RelativeSource
Mode=FindAncestorBindingContext, AncestorType ={x:Type MyVM}},
Path=SelectedContent}"
也许,您需要在 header 中描述模型的命名空间:
xmlns:viewmodel="clr-namespace:_your_namespace_.ViewModels"
并使用
SelectedValue="{Binding RelativeSource={RelativeSource
Mode=FindAncestorBindingContext, AncestorType ={x:Type viewmodel:MyVM}},
Path=SelectedContent}"
有评论here,说:
Just wanted to note here that if you want to bind to a property in the
DataContext of the RelativeSource then you must explicitly specify it:
{Binding Path=DataContext.SomeProperty, RelativeSource=.... This was
somewhat unexpected for me as a newbie when I was trying to bind to a
parent's DataContext within a DataTemplate.
这条评论值得更多关注,所以我会把它作为正确答案。
我有一个带有视图模型和一些嵌套 UI 元素的 WPF 项目。这是XAML的(相关部分):
<UserControl> // DataContext is MyVM (set programmatically)
<TreeView ItemsSource="{Binding Trees}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Subtrees}">
<StackPanel>
<ListView ItemsSource="{Binding Contents}"
SelectedValue="{Binding SelectedContent}" // won't work: Tree has no such property
SelectionMode="Single"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</UserControl>
这里是 ViewModel 的代码 class:
public class MyVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public IEnumerable<Tree> Trees { get; set; }
private object _selectedContent;
public string SelectedContent
{
get => _selectedContent;
set
{
_selectedContent = value;
OnPropertyChanged();
}
}
}
这里是 class Tree
的代码:
public class Tree
{
public IEnumerable<Tree> Subtrees { get; set; }
public IEnumerable<string> Contents { get; set; }
}
我想为所有 ListViews
在全局范围内只允许一个选择。就像here一样,我想将所有ListViews
绑定到视图模型MyVM
.
SelectedContent
问题是 ListView
的数据上下文是 Tree
,而不是来自顶级用户控件的 MyVM
。 (它应该是 Tree
,因为我们想显示 Contents
。)我知道我可以使用 SelectedValuePath
向下绑定,但是我如何向上绑定才能绑定 [=25] =] 到 MyVM
属性 SelectedContent
?
我试过SelectedValue="{Binding RelativeSource={RelativeSource AncestorType ={x:Type UserControl}}, Path=SelectedContent}"
,但是没有用。
尝试使用
SelectedValue="{Binding RelativeSource={RelativeSource
Mode=FindAncestorBindingContext, AncestorType ={x:Type MyVM}},
Path=SelectedContent}"
也许,您需要在 header 中描述模型的命名空间:
xmlns:viewmodel="clr-namespace:_your_namespace_.ViewModels"
并使用
SelectedValue="{Binding RelativeSource={RelativeSource
Mode=FindAncestorBindingContext, AncestorType ={x:Type viewmodel:MyVM}},
Path=SelectedContent}"
有评论here,说:
Just wanted to note here that if you want to bind to a property in the DataContext of the RelativeSource then you must explicitly specify it: {Binding Path=DataContext.SomeProperty, RelativeSource=.... This was somewhat unexpected for me as a newbie when I was trying to bind to a parent's DataContext within a DataTemplate.
这条评论值得更多关注,所以我会把它作为正确答案。