根据同一 ListView 中的所选项目 属性 过滤 ICollectionView - MVVM
Filter a ICollectionView based on the selected items Property in the same ListView - MVVM
我似乎无法找到解决方案。感谢任何帮助。
编辑:解决方案是通过@BionicCode 提供的过滤器逻辑组合实现的,在 XMAL 中每个 and adding a simple bool Converter er for visibility. I have also discovered that Items Control would also work for this situation and allow greater control per .
实现了一个 ListView selection
我有一个 ListView:
编辑:不幸的是,一个还不够。两个 ListViews 将起作用。请注意添加的命名空间 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
。此外,我添加了一个“后退”按钮以允许用户返回到 select 不同的类别。
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:vm="clr-namespace:WpfApp1.ViewModels"
Title="MainWindow" Height="300" Width="500" WindowStartupLocation="CenterScreen">
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="15"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Grid.Column="0" Grid.Row="1">
<Button x:Name="BackBtn" Content="Back" Command="{Binding BacktoCatView}"/>
</Grid>
<Grid Grid.Column="1" Grid.Row="1" >
<ListView x:Name="CategoryListView" ItemsSource="{Binding CategoryView}" SelectedItem="{Binding SelectedCategory}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Category}"/>
</DataTemplate>
</ListView.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectedCategoryCommand}" CommandParameter="{Binding SelectedItem, ElementName=CategoryListView}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListView>
</Grid>
<Grid Grid.Column="1" Grid.Row="1" Visibility="{Binding IsBrandView, Converter={StaticResource VisibilityConverter}}">
<ListView ItemsSource="{Binding BrandView}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Brand}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Grid> </Window>
我有一个模型:
public class Car : NotifyPropertyChanged
{
private string _brand;
public string Brand
{
get => _brand;
set
{
_brand = value;
OnPropertyChanged();
}
}
private string _category;
public string Category
{
get => _category;
set
{
_category = value;
OnPropertyChanged();
}
}
}
ListView
绑定到名为“CategoryView”的 ICollectionView
,它基于 MainViewModel 中的 ObservableCollection
“CarsCollection”。
编辑:每个 Listview
都绑定到它各自的 ICollectionView
,唉,“CategoryView”和“BrandView”。 SelectedCategory
绑定到“CategoryView”中的 SelectedItem。
MainViewModel:
public class MainViewModel : NotifyPropertyChanged
{
private ObservableCollection<Car> _carsCollection;
public ObservableCollection<Car> CarsCollection
{
get { return _carsCollection; }
set
{
_carsCollection = value;
OnPropertyChanged();
}
}
private ICollectionView _categoryView;
public ICollectionView CategoryView
{
get { return _categoryView; }
set
{
_categoryView = value;
OnPropertyChanged();
}
}
private ICollectionView _brandView;
public ICollectionView BrandView
{
get { return _brandView; }
set
{
_brandView = value;
OnPropertyChanged();
}
}
private Car _selectedCategory;
public Car SelectedCategory
{
get { return _selectedCategory; }
set
{
_selectedCategory = value;
OnPropertyChanged();
}
}
public ICommand BacktoCatView { get; private set; }
public ICommand SelectedCategoryCommand { get; private set; }
private bool _isBrandView;
public bool IsBrandView
{
get { return _isBrandView; }
set
{
_isBrandView = value;
OnPropertyChanged();
}
}
public MainViewModel()
{
CarsCollection = new ObservableCollection<Car>
{
new Car { Brand = "Chevy", Category = "Sedan" },
new Car { Brand = "Mazda", Category = "Sports Car" },
new Car { Brand = "Toyota", Category = "Sedan" },
new Car { Brand = "Honda", Category = "Sports Car" },
new Car { Brand = "Volkswagon", Category = "Sedan" },
new Car { Brand = "Tesla", Category = "Sedan" },
new Car { Brand = "Dodge", Category = "Sports Car" },
new Car { Brand = "Jeep", Category = "Off Road" },
};
BacktoCatView = new RelayCommand(ShowCategoryView);
SelectedCategoryCommand = new RelayCommand(FilterbyBrand);
//Filter by Category on app start
CategoryView = CollectionViewSource.GetDefaultView(CarsCollection);
CategoryView.Filter = item => !IsDuplicate((IEnumerable<Car>)CategoryView.SourceCollection, (Car)item);
//Setup BrandView for filtering
BrandView = (CollectionView)new CollectionViewSource { Source = CarsCollection }.View;
OnPropertyChanged("CategoryView");
OnPropertyChanged("BrandView");
}
static bool IsDuplicate(IEnumerable<Car> collection, Car target)
{
foreach (var item in collection)
{
// NOTE: Check only the items BEFORE the one in question
if (ReferenceEquals(item, target)) break;
// If more than one Category is present, only show one instance of it
if (item.Category == target.Category) return true;
}
return false;
}
private void ShowCategoryView()
{
IsBrandView = false;
}
public void FilterbyBrand()
{
IsBrandView = true;
BrandView.Filter = item => (item as Car).Category.Equals(_selectedCategory.Category, StringComparison.OrdinalIgnoreCase);
OnPropertyChanged("BrandView");
}
}
}
编辑:将 IValueConverter 添加到名为“Helpers”的新命名空间中名为“Converters”的 class 以处理可见性。我还在 Utility 命名空间中添加了一个 RelayCommand
class 来简化 ICommands 的使用。
namespace WpfApp1.Helpers
{
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var boolValue = (bool)value;
if (boolValue)
return Visibility.Visible;
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
第一个过滤器出现在构造函数中:
// Filter by Category
CategoryView = CollectionViewSource.GetDefaultView(CarsCollection);
CategoryView.Filter = item => !IsDuplicate((IEnumerable<Car>)CategoryView.SourceCollection, (Car)item);
它使用以下内容删除 Category
的重复实例:
static bool IsDuplicate(IEnumerable<Car> collection, Car target)
{
foreach (var item in collection)
{
// NOTE: Check only the items BEFORE the one in question
if (ReferenceEquals(item, target)) break;
// If more than one Category is present, only show one instance of it
if (item.Category == target.Category) return true;
}
return false;
}
此 工作完美,并在 CategoryListView 中生成以下内容:
Sedan
Sports Car
Off Road
挑战:
当用户 select 从 ListView 中选择“类别”时,我希望接下来对 IListCollection
应用第二个过滤器来过滤 ListView,以便“类别”中的每个“品牌” " 用户已 selected 显示在 ListView 中。
编辑:现在,当用户 select 属于一个类别时,他们会看到该特定 Category
的 Brand
列表。过滤对用户是无缝发生的。最重要的是,这为用户提供了应用程序启动时可用类别的即时视图,并且不需要用户在组合框中找到所需的类别。
非常感谢@BionicCode 在过滤逻辑方面的帮助。
品牌过滤器和 IsBrandView
布尔值:
private void ShowCategoryView()
{
IsBrandView = false;
}
public void FilterbyBrand()
{
IsBrandView = true;
BrandView.Filter = item => (item as Car).Category.Equals(_selectedCategory.Category, StringComparison.OrdinalIgnoreCase);
OnPropertyChanged("BrandView");
}
我通过@BionicCode 提供的过滤器逻辑组合解决了这个问题,根据这个 post 在 XMAL 中实现了一个 ListView 选择,并添加了一个简单的 bool Converter er 以提高可见性。
原post已添加解决方案。
我似乎无法找到解决方案。感谢任何帮助。
编辑:解决方案是通过@BionicCode 提供的过滤器逻辑组合实现的,在 XMAL 中每个
我有一个 ListView:
编辑:不幸的是,一个还不够。两个 ListViews 将起作用。请注意添加的命名空间 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
。此外,我添加了一个“后退”按钮以允许用户返回到 select 不同的类别。
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:vm="clr-namespace:WpfApp1.ViewModels"
Title="MainWindow" Height="300" Width="500" WindowStartupLocation="CenterScreen">
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="15"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Grid.Column="0" Grid.Row="1">
<Button x:Name="BackBtn" Content="Back" Command="{Binding BacktoCatView}"/>
</Grid>
<Grid Grid.Column="1" Grid.Row="1" >
<ListView x:Name="CategoryListView" ItemsSource="{Binding CategoryView}" SelectedItem="{Binding SelectedCategory}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Category}"/>
</DataTemplate>
</ListView.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectedCategoryCommand}" CommandParameter="{Binding SelectedItem, ElementName=CategoryListView}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListView>
</Grid>
<Grid Grid.Column="1" Grid.Row="1" Visibility="{Binding IsBrandView, Converter={StaticResource VisibilityConverter}}">
<ListView ItemsSource="{Binding BrandView}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Brand}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Grid> </Window>
我有一个模型:
public class Car : NotifyPropertyChanged
{
private string _brand;
public string Brand
{
get => _brand;
set
{
_brand = value;
OnPropertyChanged();
}
}
private string _category;
public string Category
{
get => _category;
set
{
_category = value;
OnPropertyChanged();
}
}
}
ListView
绑定到名为“CategoryView”的 ICollectionView
,它基于 MainViewModel 中的 ObservableCollection
“CarsCollection”。
编辑:每个 Listview
都绑定到它各自的 ICollectionView
,唉,“CategoryView”和“BrandView”。 SelectedCategory
绑定到“CategoryView”中的 SelectedItem。
MainViewModel:
public class MainViewModel : NotifyPropertyChanged
{
private ObservableCollection<Car> _carsCollection;
public ObservableCollection<Car> CarsCollection
{
get { return _carsCollection; }
set
{
_carsCollection = value;
OnPropertyChanged();
}
}
private ICollectionView _categoryView;
public ICollectionView CategoryView
{
get { return _categoryView; }
set
{
_categoryView = value;
OnPropertyChanged();
}
}
private ICollectionView _brandView;
public ICollectionView BrandView
{
get { return _brandView; }
set
{
_brandView = value;
OnPropertyChanged();
}
}
private Car _selectedCategory;
public Car SelectedCategory
{
get { return _selectedCategory; }
set
{
_selectedCategory = value;
OnPropertyChanged();
}
}
public ICommand BacktoCatView { get; private set; }
public ICommand SelectedCategoryCommand { get; private set; }
private bool _isBrandView;
public bool IsBrandView
{
get { return _isBrandView; }
set
{
_isBrandView = value;
OnPropertyChanged();
}
}
public MainViewModel()
{
CarsCollection = new ObservableCollection<Car>
{
new Car { Brand = "Chevy", Category = "Sedan" },
new Car { Brand = "Mazda", Category = "Sports Car" },
new Car { Brand = "Toyota", Category = "Sedan" },
new Car { Brand = "Honda", Category = "Sports Car" },
new Car { Brand = "Volkswagon", Category = "Sedan" },
new Car { Brand = "Tesla", Category = "Sedan" },
new Car { Brand = "Dodge", Category = "Sports Car" },
new Car { Brand = "Jeep", Category = "Off Road" },
};
BacktoCatView = new RelayCommand(ShowCategoryView);
SelectedCategoryCommand = new RelayCommand(FilterbyBrand);
//Filter by Category on app start
CategoryView = CollectionViewSource.GetDefaultView(CarsCollection);
CategoryView.Filter = item => !IsDuplicate((IEnumerable<Car>)CategoryView.SourceCollection, (Car)item);
//Setup BrandView for filtering
BrandView = (CollectionView)new CollectionViewSource { Source = CarsCollection }.View;
OnPropertyChanged("CategoryView");
OnPropertyChanged("BrandView");
}
static bool IsDuplicate(IEnumerable<Car> collection, Car target)
{
foreach (var item in collection)
{
// NOTE: Check only the items BEFORE the one in question
if (ReferenceEquals(item, target)) break;
// If more than one Category is present, only show one instance of it
if (item.Category == target.Category) return true;
}
return false;
}
private void ShowCategoryView()
{
IsBrandView = false;
}
public void FilterbyBrand()
{
IsBrandView = true;
BrandView.Filter = item => (item as Car).Category.Equals(_selectedCategory.Category, StringComparison.OrdinalIgnoreCase);
OnPropertyChanged("BrandView");
}
}
}
编辑:将 IValueConverter 添加到名为“Helpers”的新命名空间中名为“Converters”的 class 以处理可见性。我还在 Utility 命名空间中添加了一个 RelayCommand
class 来简化 ICommands 的使用。
namespace WpfApp1.Helpers
{
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var boolValue = (bool)value;
if (boolValue)
return Visibility.Visible;
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
第一个过滤器出现在构造函数中:
// Filter by Category
CategoryView = CollectionViewSource.GetDefaultView(CarsCollection);
CategoryView.Filter = item => !IsDuplicate((IEnumerable<Car>)CategoryView.SourceCollection, (Car)item);
它使用以下内容删除 Category
的重复实例:
static bool IsDuplicate(IEnumerable<Car> collection, Car target)
{
foreach (var item in collection)
{
// NOTE: Check only the items BEFORE the one in question
if (ReferenceEquals(item, target)) break;
// If more than one Category is present, only show one instance of it
if (item.Category == target.Category) return true;
}
return false;
}
此
Sedan
Sports Car
Off Road
挑战:
当用户 select 从 ListView 中选择“类别”时,我希望接下来对 IListCollection
应用第二个过滤器来过滤 ListView,以便“类别”中的每个“品牌” " 用户已 selected 显示在 ListView 中。
编辑:现在,当用户 select 属于一个类别时,他们会看到该特定 Category
的 Brand
列表。过滤对用户是无缝发生的。最重要的是,这为用户提供了应用程序启动时可用类别的即时视图,并且不需要用户在组合框中找到所需的类别。
非常感谢@BionicCode 在过滤逻辑方面的帮助。
品牌过滤器和 IsBrandView
布尔值:
private void ShowCategoryView()
{
IsBrandView = false;
}
public void FilterbyBrand()
{
IsBrandView = true;
BrandView.Filter = item => (item as Car).Category.Equals(_selectedCategory.Category, StringComparison.OrdinalIgnoreCase);
OnPropertyChanged("BrandView");
}
我通过@BionicCode 提供的过滤器逻辑组合解决了这个问题,根据这个 post 在 XMAL 中实现了一个 ListView 选择,并添加了一个简单的 bool Converter er 以提高可见性。
原post已添加解决方案。