Фильтрация животных с помощью радиопереключателей wpf - PullRequest
1 голос
/ 24 августа 2010

Я играю с образцом приложения WPF, которое многоуровнево в режиме Model-View-Presenter. Модель - это коллекция Animals, которая отображается в виде через привязку к свойствам в классе презентатора. XAML имеет элемент управления, который отображает всех животных в модели.

Класс модели имеет логический атрибут IsMammal. Я хочу ввести фильтр в XAML в форме группы переключателей, которая фильтрует коллекцию животных на основе атрибута IsMammal. Выбор радиокнопки «Млекопитающие» обновляет элемент управления со всеми животными, для которых значение «IsMammal» установлено в значение «истина», а когда значение переключено на «Не млекопитающие», дисплей обновляется всеми животными, которые имеют этот конкретный логический тип установить в ложь. Логика для фильтрации очень проста. Что меня беспокоит, так это расположение логики. Я не хочу никакой логики, встроенной в * .xaml.cs. Я хочу, чтобы переключение радиокнопки вызывало в презентере логику, которая сужает мою коллекцию животных, чтобы отскочить к экрану.

Некоторые указания здесь будут чрезвычайно полезны.

Спасибо

Ответы [ 2 ]

2 голосов
/ 25 августа 2010

Я предлагаю вам сделать следующее в вашем докладчике:

=> Создать поле ListCollectionView. Установите его равным «Представлению коллекции по умолчанию» вашей коллекции и используйте его в качестве источника элементов для элемента управления списком. Что-то вроде:


    public class Presenter()
    {
        private ListCollectionView lcv;

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

=> В обработчике / логике соответствующего события RadioButton отфильтруйте ListCollectionView. Что-то вроде:

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

Надеюсь, это поможет.

EDIT:

Хотя это возможно с использованием MVP, использование MVVM должно быть лучшим выбором, IMHO (и, как уже упоминалось в другом ответе) Чтобы помочь вам, я написал пример, который реализует ваши требования через 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 голос
/ 25 августа 2010

Я пришел из MVP, прежде чем изучать WPF, и пришел к выводу, что адаптация шаблона MVP к WPF в лучшем случае трудное упражнение. «Правильный» (читай, наименее разочаровывающий) подход заключается в использовании шаблона Model-View-ViewModel (MVVM), который интенсивно использует функции привязки данных в WPF, чтобы минимизировать объем кода, который заканчивается файлом просмотра.

В простейшем случае в вашей ViewModel вы получите два свойства:

  • bool FilterMammals
  • ObservableCollection MammalsToDisplay

В XAML, вы бы привязали первое к вашей группе переключателей, а второе - к ItemSource в ListBox. Среда привязки данных WPF будет вызывать ваш установщик свойств всякий раз, когда изменяется значение группы радиокнопок, и здесь вы можете фильтровать и затем обновлять список элементов.

Я не уверен, что вы знакомы с MVVM, поэтому я остановлюсь здесь. Дайте мне знать, если более подробно поможет:).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...