使用wpf radiobuttons过滤动物

时间:2010-08-24 19:46:52

标签: c# wpf xaml radio-button mvp

我正在使用以模型 - 视图 - 展示器方式分层的示例WPF应用程序。模型是动物的集合,通过绑定到演示者类中的属性显示在视图中。 XAML有一个项目控件,可以显示模型中的所有动物。

模型类有一个名为'IsMammal'的布尔属性。我想以单选按钮组的形式在XAML中引入一个过滤器,该过滤器基于'IsMammal'属性过滤动物集合。选择radiobutton'Mammals'会更新物品控制,并将所有动物的'IsMammal'值设置为true,当该值切换为'非哺乳动物'时,显示将更新为具有该特定布尔值的所有动物设为false。进行过滤的逻辑非常简单。困扰我的是逻辑的放置。我不想在* .xaml.cs中嵌入任何逻辑。我希望切换无线电按钮以触发演示器中的逻辑,使我的动物集合逐渐变细以反弹到显示器。

非常感谢这里的一些指导。

由于

2 个答案:

答案 0 :(得分:2)

我建议您在演示者中执行以下操作:

=>创建一个ListCollectionView字段。将其设置为等于集合的“默认集合视图”,并将其用作列表控件的ItemsSource。类似的东西:


    public class Presenter()
    {
        private ListCollectionView lcv;

        public Presenter()
        {
            this.lcv = (ListCollectionView)CollectionViewSource.GetDefaultView(animalsCollection);
            listControl.ItemsSource = this.lcv;
        }
    }

=>在RadioButton的相应事件的处理程序/逻辑中,过滤ListCollectionView。类似的东西:


void OnCheckedChanged()
{
     bool showMammals = radioButton.IsChecked;
     this.lcv.Filter = new Predicate((p) => (p as Animal).IsMammal == showMammals);
     this.lcv.Refresh();
}

希望这有帮助。

修改

虽然使用MVP可以做到这一点,但使用MVVM应该是更好的选择,恕我直言(并且正如其他答案所述)。为了帮助您,我编写了一个通过MVVM实现您的需求的示例。见下文:

XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
    <Grid>

        <StackPanel Orientation="Vertical">

            <RadioButton x:Name="rb1" GroupName="MyGroup" Content="IsMammal = true" Checked="rb1_Checked"/>
            <RadioButton x:Name="rb2" GroupName="MyGroup" Content="IsMammal = false" Checked="rb2_Checked"/>

            <ListBox ItemsSource="{Binding Path=AnimalsCollectionView}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=Name}"/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </StackPanel>

    </Grid>
</Window>

代码隐藏:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Threading;
using System.ComponentModel;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void rb1_Checked(object sender, RoutedEventArgs e)
        {
            (this.DataContext as ViewModel).UpdateFilter(true);
        }

        private void rb2_Checked(object sender, RoutedEventArgs e)
        {
            (this.DataContext as ViewModel).UpdateFilter(false);
        }
    }

    public class ViewModel : INotifyPropertyChanged
    {
        private ObservableCollection<Animal> animals = new ObservableCollection<Animal>();
        private ListCollectionView animalsCollectionView;

        public ListCollectionView AnimalsCollectionView
        {
            get { return this.animalsCollectionView; }
        }

        public void UpdateFilter(bool showMammals)
        {
            this.animalsCollectionView.Filter = new Predicate<object>((p) => (p as Animal).IsMammal == showMammals);
            this.animalsCollectionView.Refresh();
        }

        public ViewModel()
        { 
            this.animals.Add(new Animal() { Name = "Dog", IsMammal = true });
            this.animals.Add(new Animal() { Name = "Cat", IsMammal = true });
            this.animals.Add(new Animal() { Name = "Bird", IsMammal = false });

            this.animalsCollectionView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.animals);

        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }

        #endregion
    }

    public class Animal : INotifyPropertyChanged
    {
        private string name;
        public string Name
        {
            get { return this.name; }
            set
            {
                this.name = value;
                this.OnPropertyChanged("Name");
            }
        }

        private bool isMammal;
        public bool IsMammal
        {
            get { return this.isMammal; }
            set
            {
                this.isMammal = value;
                this.OnPropertyChanged("IsMammal");
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }

        #endregion
    }

}

答案 1 :(得分:1)

我在学习WPF之前来自MVP背景,我发现将MVP模式适应WPF是一项艰难的工作。 “正确”(阅读,最不令人沮丧)的方法是利用Model-View-ViewModel(MVVM)模式,该模式大量使用WPF的数据绑定功能,以最小化结束视图后台文件的代码量。

在最简单的情况下,您最终会在ViewModel上使用两个属性:

  • bool FilterMammals
  • ObservableCollection MammalsToDisplay

在XAML中,您可以将第一个绑定到单选按钮组,将第二个绑定到ListBox的ItemsSource。只要radiobutton组值发生变化,WPF数据绑定框架就会调用属性setter,在这里你可以过滤然后更新项目列表。

我不确定你对MVVM的熟悉程度,所以我会停在这里。如果有更多细节可以帮助我,请告诉我:)。