Модераторы: gambit, Kefir, Partizan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> CollectionView+Grouping, Использование ICollectionView  
V
    Опции темы
mparsin
Дата 12.11.2008, 19:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 26.9.2008

Репутация: нет
Всего: нет



Приветствую всех. 

Мой первый пост на этом форуме - если что, не пинайте.

Вроде бы тривиальная задача, однако не могу сообразить как её решить "in WPF way"

Вкратце:
Представьте себе обычную корзину заказа. Пользователь выбирает продукты из каталога, их количество и добавляет их в корзину. 
Есть класс, где все продукты накапливаются в коллекцию определенную как ObservableCollection<IProduct>.

Задача - показать корзину в ListBox используя DataBinding. 

Место на котором я споткнулся - группировка.  То есть я хочу, чтоб в листбоксе было 

Имя продукта  Количество Цена

Иными словами листбокс должен отображать только Group Headers без индивидуальных items.

Напрашивается использование CollectionView - так как то, что я хочу показать не что иное, как View от моей коллекции продуктов.

Проблема - как показать количество и Цену. 

Заранее спасибо за идеи и предложения
Максим.

PM MAIL   Вверх
rooks
Дата 15.11.2008, 02:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 90
Регистрация: 28.9.2008
Где: Минск

Репутация: 5
Всего: 9



Вообще нужно больше инфы давать(код IProduct, например), иначе все приходится додумывать самому. Многим это делать лень, вот никто и не отвечает)

Я тут забабахал небольшой примерчик, но без использования CollectionView. Основная фишка тут в том что, ItemsSource листбокса привязывается к твоей коллекции, а отображение мастерится через DataTemplate.

Window1.xaml:
Код
<Window x:Class="wpf_products.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300" FontSize="16">
    <Grid>
        <ListBox x:Name="listBox1" Margin="10,10,10,40">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Margin="0,1,0,1" Background="DimGray">
                        <TextBlock Margin="2" Text="{Binding Path=Наименование}"/>
                        <TextBlock Margin="2" Text="{Binding Path=Количество}"/>
                        <TextBlock Margin="2" Text="{Binding Path=Цена}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <Button Height="30" VerticalAlignment="Bottom" Margin="10" Click="Button_Click">add</Button>
    </Grid>
</Window>

Window1.xaml.cs:
Код
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Collections.ObjectModel;

namespace wpf_products
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        SomeClass sc;
        public Window1()
        {
            InitializeComponent();
            sc = new SomeClass();
            listBox1.ItemsSource = sc.list;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            sc.list.Add(new SomeProduct { Наименование = "Product1", Количество = 300, Цена = 20 });
            sc.list.Add(new SomeProduct { Наименование = "Product2", Количество = 200, Цена = 30 });
            sc.list.Add(new SomeProduct { Наименование = "Product3", Количество = 100, Цена = 40 });
        }
    }
    public interface IProduct
    {
        string Наименование { get; set; }
        int Количество { get; set; }
        int Цена { get; set; }
    }
    public class SomeProduct : IProduct
    {
        private string name;
        public string Наименование
        {
            get { return name; }
            set { name = value; }
        }
        private int count;
        public int Количество
        {
            get { return count; }
            set { count = value; }
        }
        private int cost;
        public int Цена
        {
            get { return cost; }
            set { cost = value; }
        }
    }

    public class SomeClass
    {
        public ObservableCollection<IProduct> list = new ObservableCollection<IProduct>();
    }
}


Это сообщение отредактировал(а) rooks - 15.11.2008, 02:14
PM MAIL ICQ   Вверх
mparsin
Дата 15.11.2008, 20:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 26.9.2008

Репутация: нет
Всего: нет



Привет, 

Спасибо за ответ и подсказку - почему коллективный разум безмолвствует.

В забабаханном выше примерчике есть маленькая проблемка.  Количество не является свойством продукта

Код

public interface IProduct
{
    string Name { get; set; }
    int Price { get; set; }
}

public class SomeProduct : IProduct
{
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    private int price;
    public int Price
    {
        get { return cost; }
        set { cost = value; }
    }
 }


Количество планировалось хранить в коллекции. То есть если ProductA дважды добавлен в коллекцию Order, определенную как 
Код
class Order: ObservableCollection<IProduct>
. Значит и количество у него 2. 

Но. Показывать пользователю наш Order в виде

ProductA - 2.25
ProductA - 2.25
ProductB - 3.20
ProductB - 3.20
ProductB - 3.20

тоже не интеллигентно. Напрашивается группировка. 
Группировки можно добиться минимум двумя способами. 

1. Сгруппировать данные на уровне модели. То есть добавить к классу Order метод GetGroupedByProduct() и потом забиндать к тому, что вернется из этого метода.

Недостатки этого метода очевидны. 
    Логика View переносится в Model
    Если нужно будет сгруппировать по другим признакам (например Price Range) то надо будет менять класс и так далее.


2. CollectionView, по описанию, выглядит идеальным решением. Это надстройка (View) над коллекцией. Нам нужно будет другое представление этой коллекции - мы создадим другой View.

Проблему, которую я не знаю как решить я описал в моем предыдущем посте.

Вот, что я могу сделать

Код

<Window x:Class="Grouping.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Grouping="clr-namespace:Grouping"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <Grouping:Order x:Key="order"/>
        <Grouping:GroupByIDConverter x:Key="GroupByIDConverter"/>
        <CollectionViewSource x:Key="cvs" Source="{Binding Source={StaticResource order}}">
            <CollectionViewSource.GroupDescriptions>
                <PropertyGroupDescription PropertyName="Name"/>
            </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>


    </Window.Resources>
    <StackPanel>
        <ListBox x:Name="lbProducts" ItemsSource="{Binding Source={StaticResource cvs}, Path=Groups}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Path=Name}"/>
                        <TextBlock Text="{Binding Path=Count}"/>
                    </StackPanel>

                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </StackPanel>
</Window>



То есть мы реализуем binding не к коллекции самой а к группам в этой коллекции. 
Но для того, что мне нужно я должен показать Количество Items in group а это не является свойством группы. И второе я должен показать цену, которая так же не является свойством группы, а является свойством элемента группы. 

Я тут забабахал небольшой примерчик, но без использования CollectionView.
Кстати, насколько я понимаю ItemsControl - ты не совсем прав. Ты не использовал CollectionView напрямую. Каждый раз когда мы bind'аем коллекцию или DataTable к ItemsControl - CollectionView создается за сценой. Там WPF хранит информацию о текущем выделенном элементе, например.

Надеюсь сейчас я дал больше информации. 

Меня напрягает тривиальность задачи. Ведь, наверняка, проблему "пользовательской корзины" решили в WPF/Silverlight уже несколько тысяч программистов.  smile 
PM MAIL   Вверх
rooks
Дата 16.11.2008, 00:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 90
Регистрация: 28.9.2008
Где: Минск

Репутация: 5
Всего: 9



Информации теперь более чем достаточно, а самое главное - понятно зачем нужно группировать. Собстенно посидев немного в дебаггере и поизучав внутренюю структуру CollectionViewSource, написал вторую версию минипримера:

Код
<Window x:Class="wpf_products.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:src="clr-namespace:wpf_products"
    Title="Window1" Height="300" Width="300" FontSize="16">
    <Window.Resources>
        <CollectionViewSource x:Key="cvs">
            <CollectionViewSource.GroupDescriptions>
                <PropertyGroupDescription PropertyName="Name"/>
            </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
    </Window.Resources>
    <Grid>
        <ListBox x:Name="listBox1" Margin="10,10,10,40" ItemsSource="{Binding Source={StaticResource cvs}, Path=Groups}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Margin="0,1,0,1" Background="DimGray">
                        <TextBlock Margin="2" Text="{Binding Path=Name}"/>
                        <TextBlock Margin="2" Text="{Binding Path=Items[0].Price}"/>
                        <TextBlock Margin="2" Text="{Binding Path=Items.Count}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <Button Height="30" VerticalAlignment="Bottom" Margin="10" Click="Button_Click">add</Button>
    </Grid>
</Window>


Код
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Collections.ObjectModel;
using System.Windows.Data;

namespace wpf_products
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        SomeClass sc;
        public Window1()
        {
            InitializeComponent();
            sc = new SomeClass();
            CollectionViewSource cvs1 = ((CollectionViewSource)this.Resources["cvs"]);
            cvs1.Source = sc.list;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            sc.list.Add(new SomeProduct { Name = "ProductA", Price = 2.25 });
            sc.list.Add(new SomeProduct { Name = "ProductB", Price = 3.20 });
            sc.list.Add(new SomeProduct { Name = "ProductC", Price = 2 });
            sc.list.Add(new SomeProduct { Name = "ProductC", Price = 2 });
        }
    }

    public interface IProduct
    {
        string Name { get; set; }
        double Price { get; set; }
    }

    public class SomeProduct : IProduct
    {
        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        private double price;
        public double Price
        {
            get { return price; }
            set { price = value; }
        }
    }

    public class SomeClass
    {
        public ObservableCollection<IProduct> list = new ObservableCollection<IProduct>();
    }
}


PM MAIL ICQ   Вверх
mparsin
Дата 17.11.2008, 16:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 26.9.2008

Репутация: нет
Всего: нет



Спасибо, всё правильно, молодец!

Не сообразил, что у CollectionViewGroup  есть Items.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | WPF и Silverlight | Следующая тема »


 




[ Время генерации скрипта: 0.0479 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.