C# 如何在嵌套的ListView中访问SelectedItem
这几天我一直在挣扎。我找到了很多链接,但没有一个对我有帮助。我是WPF的初学者。 我只需要在嵌套的ListView中访问SelectedItem属性。 当然,Outter ListView绑定是有效的。 我做了一些研究后尝试了什么,但没有成功,即使我真的不明白为什么它没有成功:C# 如何在嵌套的ListView中访问SelectedItem,c#,wpf,listview,mvvm,C#,Wpf,Listview,Mvvm,这几天我一直在挣扎。我找到了很多链接,但没有一个对我有帮助。我是WPF的初学者。 我只需要在嵌套的ListView中访问SelectedItem属性。 当然,Outter ListView绑定是有效的。 我做了一些研究后尝试了什么,但没有成功,即使我真的不明白为什么它没有成功: <Window x:Class="ListViewRef.View.ListViewWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xa
<Window x:Class="ListViewRef.View.ListViewWindow"
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:vm="clr-namespace:ListViewRef.ViewModel"
xmlns:local="clr-namespace:ListViewRef.View"
mc:Ignorable="d"
Title="Nested List Views" Height="450" Width="800">
<Window.DataContext>
<vm:MainVM/>
</Window.DataContext>
<StackPanel x:Name="Global">
<TextBlock Text="{Binding MainTitle}"/>
<ListView ItemsSource="{Binding Path=SourceCollection}"
SelectedItem="{Binding Path=OutterSelectedItem}"
>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Title}"/>
<TextBlock Text="Now second ListView:"/>
<ListView ItemsSource="{Binding Strings}"
SelectedItem="{Binding Path=NestedSelectedItem,
RelativeSource={RelativeSource AncestorType=vm:MainVM},
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
></ListView>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Window>
和视图模型:
using ListViewRef.Model;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
namespace ListViewRef.ViewModel
{
public class MainVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string mainTitle;
public string MainTitle {
get { return mainTitle; }
set { mainTitle = value; OnPropertyChanged(nameof(MainTitle)); }
}
private string nestedSelectedItem;
public string NestedSelectedItem {
get { return nestedSelectedItem; }
set
{
nestedSelectedItem = value;
MessageBox.Show("NestedSelectedItem: " + nestedSelectedItem);
OnPropertyChanged(nameof(NestedSelectedItem));
}
}
private string outterSelectedItem;
public string OutterSelectedItem {
get { return outterSelectedItem; }
set
{
outterSelectedItem = value;
MessageBox.Show("OutterSelectedItem: " + OutterSelectedItem);
OnPropertyChanged(nameof(OutterSelectedItem));
}
}
public ObservableCollection<ClassWithObsList> SourceCollection { get; set; }
public MainVM()
{
MainTitle = "Title of the Grid";
SourceCollection = new ObservableCollection<ClassWithObsList> {
new ClassWithObsList("First Title", new ObservableCollection<string> { "First", "Second"}),
new ClassWithObsList("Second Title", new ObservableCollection<string> { "Third", "Fourth"}),
new ClassWithObsList("Third Title", new ObservableCollection<string> { "Fifth", "Sixth"}),
};
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
使用ListViewRef.Model;
使用System.Collections.ObjectModel;
使用系统组件模型;
使用System.Windows;
名称空间ListViewRef.ViewModel
{
公共类MainVM:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
私有字符串主标题;
公共字符串主标题{
获取{return mainttitle;}
设置{maintTitle=value;OnPropertyChanged(nameof(maintTitle));}
}
私有字符串nestedSelectedItem;
公共字符串NestedSelectedItem{
获取{return nestedSelectedItem;}
设置
{
nestedSelectedItem=值;
MessageBox.Show(“NestedSelectedItem:+NestedSelectedItem”);
OnPropertyChanged(名称(NestedSelectedItem));
}
}
私有字符串outterSelectedItem;
公共字符串OutterSelectedItem{
获取{return outterSelectedItem;}
设置
{
outterSelectedItem=值;
MessageBox.Show(“OutterSelectedItem:+OutterSelectedItem”);
OnPropertyChanged(名称为(OutterSelectedItem));
}
}
公共ObservableCollection源集合{get;set;}
公共MainVM()
{
mainttitle=“网格的标题”;
SourceCollection=新的ObservableCollection{
新类WithObsList(“第一个标题”,新的ObservableCollection{“第一”,“第二”}),
新类WithObsList(“第二个标题”,新的ObservableCollection{“第三个”,“第四个”}),
新类WithObsList(“第三个标题”,新的ObservableCollection{“第五个”,“第六个”}),
};
}
私有void OnPropertyChanged(字符串propertyName)
{
if(PropertyChanged!=null)
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
}
}
模型类:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace ListViewRef.Model
{
public class ClassWithObsList : INotifyPropertyChanged
{
private string title;
public string Title {
get { return title; }
set {
title = value;
OnPropertyChanged(nameof(Title));
}
}
public ObservableCollection<string> Strings { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public ClassWithObsList(string title, ObservableCollection<string> strings)
{
Title = title ?? throw new ArgumentNullException(nameof(title));
Strings = strings ?? throw new ArgumentNullException(nameof(strings));
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
使用系统;
使用System.Collections.ObjectModel;
使用系统组件模型;
名称空间ListViewRef.Model
{
带有obslist的公共类:INotifyPropertyChanged
{
私有字符串标题;
公共字符串标题{
获取{返回标题;}
设置{
标题=价值;
财产变更(名称(所有权));
}
}
公共ObservableCollection字符串{get;set;}
公共事件属性更改事件处理程序属性更改;
公共类WithObsList(字符串标题、ObservableCollection字符串)
{
Title=Title??抛出新的ArgumentNullException(nameof(Title));
Strings=Strings??抛出新ArgumentNullException(nameof(Strings));
}
私有void OnPropertyChanged(字符串propertyName)
{
if(PropertyChanged!=null)
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
}
}
中的
类型vm:MainVM
不是内部ListView的祖先类型,因为它不是可视树或逻辑树的一部分
AncestorType必须是UI元素,例如外部ListView。您可以通过嵌套属性路径通过其DataContext访问该属性:
SelectedItem="{Binding Path=DataContext.NestedSelectedItem,
RelativeSource={RelativeSource AncestorType=ListView}, ...}
请注意,由于您没有设置ListView的
视图
属性,因此您也可以使用更简单的基类ListBox而不是ListView:
<ListBox ItemsSource="{Binding Path=SourceCollection}"
SelectedItem="{Binding Path=OutterSelectedItem}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Title}"/>
<TextBlock Text="Now second ListView:"/>
<ListBox ItemsSource="{Binding Strings}"
SelectedItem="{Binding Path=DataContext.NestedSelectedItem,
RelativeSource={RelativeSource AncestorType=ListBox},
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
非常感谢您的帮助和解释,这解决了问题。我现在理解对了吗,RelativeSource设置了我要绑定到的UI元素的DataContext?不完全是“what DataContext”,而是绑定的源对象。源由绑定的source、RelativeSource或ElementName属性设置,如果未设置这些属性,则由目标元素的DataContext设置。DataContext属性的值由子元素从其父元素继承,这就是为什么ListView的DataContext是窗口的DataContext。我在推导中看到了错误。非常感谢你,克莱门斯。这很有帮助。
<ListBox ItemsSource="{Binding Path=SourceCollection}"
SelectedItem="{Binding Path=OutterSelectedItem}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Title}"/>
<TextBlock Text="Now second ListView:"/>
<ListBox ItemsSource="{Binding Strings}"
SelectedItem="{Binding Path=DataContext.NestedSelectedItem,
RelativeSource={RelativeSource AncestorType=ListBox},
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>