none
Принцип работы прокси класса CollectionViewSource в WPF RRS feed

  • Вопрос

  • По причине изложенной здесь возникла необходимость разобраться с принципом работы прокси класса CollectionViewSource да и в целом системы представления в WPF.

    Цель написать самостоятельно такую систему для приложений WinRT.

    Конкретно не понятно как класс CollectionViewSource ложиться поверх коллекции. То есть мы задаем его как ресурс, а затем в Source биндинга указываем его и привязка получает отредактированную представлением коллекцию. Кто нибудь вникал в углубленно как это работает?


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    25 ноября 2012 г. 8:45
    Отвечающий

Ответы

  • В общем, что то я опять запутался в IEnumerable, вот вам универсальный класс для фильтрации и сортировки. Правда результат надо брать не из самого объекта, а из поля View:

    public class AlCollectionViewSource<T> : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void OnPropertyChanged(string p_propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(p_propertyName));
            }
        }
    
        IEnumerable<T> _source;
    
        private Func<T, bool> _filter = null;
    
        public Func<T, bool> Filter
        {
            get
            {
                return _filter;
            }
            set
            {
                if (_filter != value)
                {
                    _filter = value;
                    OnPropertyChanged("View");
                }
            }
        }
    
        private string _orderPropertyName = null;
    
        public string OrderPropertyName 
        {
            get
            {
                return _orderPropertyName;
            }
            set
            {
                if (_orderPropertyName != value)
                {
                    _orderPropertyName = value;
                    OnPropertyChanged("View");
                }
            }
        }
    
        public IEnumerable<T> View
        {
            get
            {
                IEnumerable<T> result = _source;
                Func<T, bool> filter = Filter;
                if (filter != null)
                {
                    result = result.Where(item => filter(item));
                }
                if (!string.IsNullOrWhiteSpace(OrderPropertyName))
                {
                    result = result.OrderBy(
                        item =>
                        {
                            Type type = item.GetType();
                            PropertyInfo property = type.GetTypeInfo().GetDeclaredProperty(OrderPropertyName);
                            return property.GetValue(item);
                        });
                }
                else
                {
                    if (OrderPropertyName == "")
                    {
                        result = result.OrderBy(item => item);
                    }
                }
                return result;
            }
        }
    
        public AlCollectionViewSource(IEnumerable<T> p_source)
        {
            _source = p_source;
            OnPropertyChanged("View");
        }
    }

    Ну и пример, как этим воспользоваться. Вот мой демо класс:

    public class Person
    {
        public string LastName { get; set; }
    
        public static List<Person> GetPersonCollection()
        {
            List<Person> result = new List<Person>();
            result.Add(new Person { LastName = "Сидоров" });
            result.Add(new Person { LastName = "Федоров" });
            result.Add(new Person { LastName = "Иванов" });
            result.Add(new Person { LastName = "Петров" });
            return result;
        }
    }

    Вот пример ViewModel:

    public class MyViewModel
    {
        public ICommand SearchCommand { get; private set; }
    
        public ICommand OrderCommand { get; private set; }
    
        public AlCollectionViewSource<Person> Items { get; private set; }
    
        public string FilterString { get; set; }
    
        public MyViewModel()
        {
            Items = new AlCollectionViewSource<Person>(Person.GetPersonCollection());
            SearchCommand = new MyCommand(() => Items.Filter = item => item.LastName.ToLower().Contains(FilterString.ToLower()));
            OrderCommand = new MyCommand(() => Items.OrderPropertyName = "LastName");
        }
    }

    Вот, разметка:

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <TextBox Text="{Binding Path=FilterString,Mode=TwoWay}" Width="150" Margin="5" />
            <Button Content="Фильтр!" Command="{Binding SearchCommand}" />
            <Button Content="Сортировка!" Command="{Binding OrderCommand}" />
        </StackPanel>
        <ListView x:Name="lvMain" Grid.Row="1" DataContext="{Binding Items}" ItemsSource="{Binding View}" DisplayMemberPath="LastName" />
    </Grid>
    Да, незабудьте экземпляр класса MyViewModel пдсунуть в DataContext окна.

    Это же. с небольшими моими пояснениями и демонстрацией работы, можно найти у меня в блоге.

    • Помечено в качестве ответа LXGDARKEditor 25 ноября 2012 г. 18:17
    25 ноября 2012 г. 17:17
    Отвечающий

Все ответы

  • Для того, чтобы написать свой такой класс, необходимо реализовать в нем поддержку интерфейсов INotifyCollectionChanged и IEnumerable. Все, теоретически должно заработать. Если будет время, то сегодня попробую написать такой класс.

    25 ноября 2012 г. 9:16
    Отвечающий
  • В общем, что то я опять запутался в IEnumerable, вот вам универсальный класс для фильтрации и сортировки. Правда результат надо брать не из самого объекта, а из поля View:

    public class AlCollectionViewSource<T> : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void OnPropertyChanged(string p_propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(p_propertyName));
            }
        }
    
        IEnumerable<T> _source;
    
        private Func<T, bool> _filter = null;
    
        public Func<T, bool> Filter
        {
            get
            {
                return _filter;
            }
            set
            {
                if (_filter != value)
                {
                    _filter = value;
                    OnPropertyChanged("View");
                }
            }
        }
    
        private string _orderPropertyName = null;
    
        public string OrderPropertyName 
        {
            get
            {
                return _orderPropertyName;
            }
            set
            {
                if (_orderPropertyName != value)
                {
                    _orderPropertyName = value;
                    OnPropertyChanged("View");
                }
            }
        }
    
        public IEnumerable<T> View
        {
            get
            {
                IEnumerable<T> result = _source;
                Func<T, bool> filter = Filter;
                if (filter != null)
                {
                    result = result.Where(item => filter(item));
                }
                if (!string.IsNullOrWhiteSpace(OrderPropertyName))
                {
                    result = result.OrderBy(
                        item =>
                        {
                            Type type = item.GetType();
                            PropertyInfo property = type.GetTypeInfo().GetDeclaredProperty(OrderPropertyName);
                            return property.GetValue(item);
                        });
                }
                else
                {
                    if (OrderPropertyName == "")
                    {
                        result = result.OrderBy(item => item);
                    }
                }
                return result;
            }
        }
    
        public AlCollectionViewSource(IEnumerable<T> p_source)
        {
            _source = p_source;
            OnPropertyChanged("View");
        }
    }

    Ну и пример, как этим воспользоваться. Вот мой демо класс:

    public class Person
    {
        public string LastName { get; set; }
    
        public static List<Person> GetPersonCollection()
        {
            List<Person> result = new List<Person>();
            result.Add(new Person { LastName = "Сидоров" });
            result.Add(new Person { LastName = "Федоров" });
            result.Add(new Person { LastName = "Иванов" });
            result.Add(new Person { LastName = "Петров" });
            return result;
        }
    }

    Вот пример ViewModel:

    public class MyViewModel
    {
        public ICommand SearchCommand { get; private set; }
    
        public ICommand OrderCommand { get; private set; }
    
        public AlCollectionViewSource<Person> Items { get; private set; }
    
        public string FilterString { get; set; }
    
        public MyViewModel()
        {
            Items = new AlCollectionViewSource<Person>(Person.GetPersonCollection());
            SearchCommand = new MyCommand(() => Items.Filter = item => item.LastName.ToLower().Contains(FilterString.ToLower()));
            OrderCommand = new MyCommand(() => Items.OrderPropertyName = "LastName");
        }
    }

    Вот, разметка:

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <TextBox Text="{Binding Path=FilterString,Mode=TwoWay}" Width="150" Margin="5" />
            <Button Content="Фильтр!" Command="{Binding SearchCommand}" />
            <Button Content="Сортировка!" Command="{Binding OrderCommand}" />
        </StackPanel>
        <ListView x:Name="lvMain" Grid.Row="1" DataContext="{Binding Items}" ItemsSource="{Binding View}" DisplayMemberPath="LastName" />
    </Grid>
    Да, незабудьте экземпляр класса MyViewModel пдсунуть в DataContext окна.

    Это же. с небольшими моими пояснениями и демонстрацией работы, можно найти у меня в блоге.

    • Помечено в качестве ответа LXGDARKEditor 25 ноября 2012 г. 18:17
    25 ноября 2012 г. 17:17
    Отвечающий
  • C# не беда, я его уже и без конвертера не плохо понимать начал :)

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    25 ноября 2012 г. 18:18
    Отвечающий