[WPF] Check ListBox и MVVM
От: Grog13 Финляндия  
Дата: 09.12.09 10:05
Оценка:
Приветствую.

Есть такой списочек: List<MyData>
public class MyData
{
    public String MyName { get; set; }
}


Мне надо вывести его в ListBox таким образом, что бы можно было выбрать несколько элементов.
Далее, есть TextBlock в который надо вывести все выбранные MyData.MyName через запятую.
И есть кнопочка, по нажатию на которую, надо очистить все выбранные элементы.

Что я делаю:
Во ViewModel есть ObservableCollection<MyData> в который и попадает нужный список.

Во View:
            <ListBox ItemsSource="{Binding Path=MyList}" SelectionMode="Multiple">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal" Margin="0,5,0,5" >
                            <CheckBox IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem} }, Path=IsSelected, Mode=TwoWay}" />
                            <TextBlock Text="{Binding Path=MyName}" />
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>


Так все работает. Выбранные элементы отмечаются checkbox'ом.
Теперь как мне в TextBlock вывести все выбранные элементы?
И как мне во ViewModel узнать выбранные элементы? И как мне из ViewModel очистить выбранные элементы?
Re: [WPF] Check ListBox и MVVM
От: Codechanger Россия  
Дата: 09.12.09 10:13
Оценка:
Здравствуйте, Grog13, Вы писали:
G>Теперь как мне в TextBlock вывести все выбранные элементы?
IValueConverter?
G>И как мне во ViewModel узнать выбранные элементы? И как мне из ViewModel очистить выбранные элементы?
Завести свойство во ViewModel.
Re: [WPF] Check ListBox и MVVM
От: notacat  
Дата: 09.12.09 10:21
Оценка:
У ListBox есть свойство SelectedItems — используйте его + свой какой-нибудь конвертер, чтобы это в текстбокс вывести.
Во ViewModel как узнать — ну лучше всего во ViewModel же завести еще одно свойство SelectedItems и к нему ListBox прибайндить (не уверена, что получится). Если вера позволяет из ViewModel напрямую c ListBox'ом работать — то вообще все должно быть просто.
Re[2]: [WPF] Check ListBox и MVVM
От: Grog13 Финляндия  
Дата: 09.12.09 10:48
Оценка:
Здравствуйте, Codechanger, Вы писали:

C>Здравствуйте, Grog13, Вы писали:

G>>Теперь как мне в TextBlock вывести все выбранные элементы?
C>IValueConverter?

Сделал так:
<TextBlock Text="{Binding ElementName=MyLB, Path=SelectedItems, Converter={StaticResource MyConverter}}" />


    public class MyConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return "Hello";
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new System.NotImplementedException();
        }
    }


Но это счастье вызывается почему-то только один раз, когда value = null;
При изменении SelectedItems почему-то не вызывается. (Поставил breakpoint на точке return "Hello")
Однако, если в XAML написать так:

<TextBlock Text="{Binding ElementName=MyLB, Path=SelectedItems.Count}" />


То, там ожидаемо получается правильное число выбранных элементов.
Где я ошибся с конвертером?

G>>И как мне во ViewModel узнать выбранные элементы? И как мне из ViewModel очистить выбранные элементы?

C>Завести свойство во ViewModel.

А можно по-конкретнее? Как можно изменять это свойство из XAML?
Если биндиться к SelectedItems то получаю такую ошибку:

'SelectedItems' property is read-only and cannot be set from markup.
Re[2]: [WPF] Check ListBox и MVVM
От: Grog13 Финляндия  
Дата: 09.12.09 10:51
Оценка:
Здравствуйте, notacat, Вы писали:

N>У ListBox есть свойство SelectedItems — используйте его + свой какой-нибудь конвертер, чтобы это в текстбокс вывести.


Вот что-то не получается...

N>Во ViewModel как узнать — ну лучше всего во ViewModel же завести еще одно свойство SelectedItems и к нему ListBox прибайндить (не уверена, что получится).


Не получается. Потому, что SelectedItems readonly

N>Если вера позволяет из ViewModel напрямую c ListBox'ом работать — то вообще все должно быть просто.


Хотелось бы в рамках MVVM DumbView и всё такое.
Re[3]: [WPF] Check ListBox и MVVM
От: Codechanger Россия  
Дата: 09.12.09 11:11
Оценка:
Здравствуйте, Grog13, Вы писали:

G>Здравствуйте, Codechanger, Вы писали:


C>>Здравствуйте, Grog13, Вы писали:

G>>>Теперь как мне в TextBlock вывести все выбранные элементы?
C>>IValueConverter?

G>Но это счастье вызывается почему-то только один раз, когда value = null;

Ну все правильно, потому что SelectedItems — не ObservableCollection.
Есть еще путь — завести SelectedItems во VIewModel и по SelectionChanged его обновлять. Очистку проводить, скажем, по вызову события OnNeedsClearSelectedItems у ViewModel, а контрол с листбоксом на него подписать.
Re[3]: [WPF] Check ListBox и MVVM
От: notacat  
Дата: 09.12.09 11:47
Оценка:
То, что свойство readonly — это полбеды, можно же просто направление байндинга поменять. Хуже, что это не ObservableCollection, не будет уведомлений об изменении.

В общем, у меня подобная задача решается все-таки бОльшей частью в коде. Т.е. сделан контрол, в котором есть ListBox и TextBox, кнопки и т.д.
У контрола есть свойства — большая коллекция, CollectionView поверх этой коллекции (используется как ItemsSource для ListBox'а), коллекция выбранных айтемов. Все действия делаются в обработчиках событий.

По отношению к модели я этот свой контрол рассматриваю как аналог любого другого контрола типа ListBox'а.
Использую его для редактирования нескольких разных коллекций.
Re[4]: [WPF] Check ListBox и MVVM
От: Codechanger Россия  
Дата: 09.12.09 12:33
Оценка:
Здравствуйте, notacat, Вы писали:

N>То, что свойство readonly — это полбеды, можно же просто направление байндинга поменять. Хуже, что это не ObservableCollection, не будет уведомлений об изменении.


N>В общем, у меня подобная задача решается все-таки бОльшей частью в коде. Т.е. сделан контрол, в котором есть ListBox и TextBox, кнопки и т.д.

N>У контрола есть свойства — большая коллекция, CollectionView поверх этой коллекции (используется как ItemsSource для ListBox'а), коллекция выбранных айтемов. Все действия делаются в обработчиках событий.

N>По отношению к модели я этот свой контрол рассматриваю как аналог любого другого контрола типа ListBox'а.

N>Использую его для редактирования нескольких разных коллекций.

Кстати, реализацией ICollectionView никто не заделится, часом? Если, кто-то, конечно, занимался кастомной имплементацией...
Re[5]: [WPF] Check ListBox и MVVM
От: Экселенц Россия  
Дата: 25.04.11 09:10
Оценка:
Привет, всем!
Вопрос немного другой, но уж больно подходящее название темы, не пинайте.
Есть у меня некий класс со строковым свойством.

public class MyClass {
    public String name { get; set; }
}


Есть коллекция объектов этого класса, которую возвращают сервиса:

List<MyClass> myCollection;


В xaml есть ItemsControl, ItemsSource которого биндится на myCollection:

<ItemsControl ItemsSource="{Binding Path=myCollection}" />


Для этого ItemsControl есть DataTemplate, который заставляет каждый итем стать чекбоксом, имя чекбокса берётся из MyClass.name:

<DataTemplate>
    <CheckBox Content="{Binding Path=name}" />
</DataTemplate>


Собственно, весь этот код используется для динамической генерации чекбоксов на форме.
Далее, мне необходимо при инициализации формы не только вывести список чекбоксов, но и для каждого чекбокса указать его начальное состояние, checked он или unchecked, для чего забиндить ItemsControl.IsChecked на что-то:

<DataTemplate>
    <CheckBox Content="{Binding Path=name}" IsChecked="???" />
</DataTemplate>


Как именно хранить состояние чекбоксов, я волен выбирать сам. Проще всего добавить свойство IsChecked в MyClass, тогда можно биндится непосредственно на него и проблем нет, но это крайне кривой подход, т.к. MyClass — это класс модели и я не хочу в нём хранить визуальные свойства. Кроме того, такой подход не работает, если на форме две группы чекбоксов из одного ItemsSource, которые необходимо чекать независимо друг от друга.
Другой поход, который пришёл в голову, это выставлять для биндинга в ItemsControl не List<MyClass>, а List<MyProxyClass>, где MyProxyClass аггрегирует MyClass, выставляя наружу его свойства, плюс добавляет необходимое свойство IsChecked, примерно так:

public class MyProxyClass {
    private MyClass _myClass;

    public MyProxyClass(MyClass myClass) { _myClass = myClass; }

    public String name {
         get { return _myClass.name; }
         set { _myClass.name = value; }
    }

    public Nullable<bool> IsChecked { get; set; }
}


Тогда, получив от сервисов List<MyClass>, можно ручкам создать List<MyProxyClass> и выставить его для биндинга. Реально, чекнутые итемы я собираюсь хранить в отдельной коллекции:

List<MyClass> myCheckedCollection;


данные из которой использовать при инициализации List<MyProxyClass>, ну и обновлять эту коллекцию при изменении свойства MyProxyClass.IsChecked.
Но этот способ тоже отдаёт какой-то кривизной.
Последнее, что пришло в голову, это использовать конвертер. Тогда ItemsControl.IsChecked будет биндится на текущий MyClass через RelativeSource self, а конвертер будет принимать MyClass, искать его в списке myCheckedCollection и возвращать соответствующий результат. Вроде бы это будет хорошо работать при начальной инициализации, однако мне нужно, во-первых, чтобы когда юзер чекнет или анчекнет какой-нибудь чекбокс myCheckedCollection сообветствующим образом бы обновился и наоборот, если в коде я добавлю в myCheckedCollection новый MyClass, то соответствующий чекбокс стал бы чекнутым. Я сомневаюсь в своей способности заставить конвертер делать всё это.
Как сделали бы вы?
Re[6]: [WPF] Check ListBox и MVVM
От: MxMsk Португалия  
Дата: 25.04.11 09:41
Оценка:
Здравствуйте, Экселенц, Вы писали:

Э>Как сделали бы вы?

Вариант с MyProxyClass. Он наиболее надежен в плане взаимодействия с UI, упрощает работу с IsChecked в коде и разработку шаблонов в XAML. К тому же это решение более гибкое, а то мало ли какие еще понадобятся свойства визуального толка в будущем. В нашем проекте в общем модуле даже есть заготовки, которые оборачивают объект, добавляя ему свойства типа IsSelected и IsExpanded. При этом не обязательно воспроизводить в MyProxyClass все свойства MyClass. Можно сделать что-то вроде:
public class MyProxyClass {
    private readonly MyClass _myClass;

    public MyProxyClass(MyClass myClass) { _myClass = myClass; }

    public MyClass Source {
         get { return _myClass; }
    }

    public Nullable<bool> IsChecked { get; set; }
}

и не париться с переделкой MyProxyClass при изменении MyClass.
Re[7]: [WPF] Check ListBox и MVVM
От: Экселенц Россия  
Дата: 25.04.11 09:51
Оценка:
Здравствуйте, MxMsk, Вы писали:
MM>Вариант с MyProxyClass.
Спасибо. Да, я согласен, что не обязательно воспроизводить в MyProxyClass все свойства MyClass, можно сделать и как у вас. В принципе мне тоже этот способ кажется достаточно простым и надёжным, но всё же хотелось бы узнать, не существует ли способов обойтись без прокси-класса, а использовать конвертер или какой-то другой механизм. Может кто-нибудь ещё подскажет.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.