public class MyData
{
public String MyName { get; set; }
}
Мне надо вывести его в ListBox таким образом, что бы можно было выбрать несколько элементов.
Далее, есть TextBlock в который надо вывести все выбранные MyData.MyName через запятую.
И есть кнопочка, по нажатию на которую, надо очистить все выбранные элементы.
Что я делаю:
Во ViewModel есть ObservableCollection<MyData> в который и попадает нужный список.
Так все работает. Выбранные элементы отмечаются checkbox'ом.
Теперь как мне в TextBlock вывести все выбранные элементы?
И как мне во ViewModel узнать выбранные элементы? И как мне из ViewModel очистить выбранные элементы?
Здравствуйте, Grog13, Вы писали: G>Теперь как мне в TextBlock вывести все выбранные элементы?
IValueConverter? G>И как мне во ViewModel узнать выбранные элементы? И как мне из ViewModel очистить выбранные элементы?
Завести свойство во ViewModel.
У ListBox есть свойство SelectedItems — используйте его + свой какой-нибудь конвертер, чтобы это в текстбокс вывести.
Во ViewModel как узнать — ну лучше всего во ViewModel же завести еще одно свойство SelectedItems и к нему ListBox прибайндить (не уверена, что получится). Если вера позволяет из ViewModel напрямую c ListBox'ом работать — то вообще все должно быть просто.
Здравствуйте, Codechanger, Вы писали:
C>Здравствуйте, Grog13, Вы писали: G>>Теперь как мне в TextBlock вывести все выбранные элементы? C>IValueConverter?
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 написать так:
То, там ожидаемо получается правильное число выбранных элементов.
Где я ошибся с конвертером?
G>>И как мне во ViewModel узнать выбранные элементы? И как мне из ViewModel очистить выбранные элементы? C>Завести свойство во ViewModel.
А можно по-конкретнее? Как можно изменять это свойство из XAML?
Если биндиться к SelectedItems то получаю такую ошибку:
'SelectedItems' property is read-only and cannot be set from markup.
Здравствуйте, notacat, Вы писали:
N>У ListBox есть свойство SelectedItems — используйте его + свой какой-нибудь конвертер, чтобы это в текстбокс вывести.
Вот что-то не получается...
N>Во ViewModel как узнать — ну лучше всего во ViewModel же завести еще одно свойство SelectedItems и к нему ListBox прибайндить (не уверена, что получится).
Не получается. Потому, что SelectedItems readonly
N>Если вера позволяет из ViewModel напрямую c ListBox'ом работать — то вообще все должно быть просто.
Здравствуйте, Grog13, Вы писали:
G>Здравствуйте, Codechanger, Вы писали:
C>>Здравствуйте, Grog13, Вы писали: G>>>Теперь как мне в TextBlock вывести все выбранные элементы? C>>IValueConverter?
G>Но это счастье вызывается почему-то только один раз, когда value = null;
Ну все правильно, потому что SelectedItems — не ObservableCollection.
Есть еще путь — завести SelectedItems во VIewModel и по SelectionChanged его обновлять. Очистку проводить, скажем, по вызову события OnNeedsClearSelectedItems у ViewModel, а контрол с листбоксом на него подписать.
То, что свойство readonly — это полбеды, можно же просто направление байндинга поменять. Хуже, что это не ObservableCollection, не будет уведомлений об изменении.
В общем, у меня подобная задача решается все-таки бОльшей частью в коде. Т.е. сделан контрол, в котором есть ListBox и TextBox, кнопки и т.д.
У контрола есть свойства — большая коллекция, CollectionView поверх этой коллекции (используется как ItemsSource для ListBox'а), коллекция выбранных айтемов. Все действия делаются в обработчиках событий.
По отношению к модели я этот свой контрол рассматриваю как аналог любого другого контрола типа ListBox'а.
Использую его для редактирования нескольких разных коллекций.
Здравствуйте, notacat, Вы писали:
N>То, что свойство readonly — это полбеды, можно же просто направление байндинга поменять. Хуже, что это не ObservableCollection, не будет уведомлений об изменении.
N>В общем, у меня подобная задача решается все-таки бОльшей частью в коде. Т.е. сделан контрол, в котором есть ListBox и TextBox, кнопки и т.д. N>У контрола есть свойства — большая коллекция, CollectionView поверх этой коллекции (используется как ItemsSource для ListBox'а), коллекция выбранных айтемов. Все действия делаются в обработчиках событий.
N>По отношению к модели я этот свой контрол рассматриваю как аналог любого другого контрола типа ListBox'а. N>Использую его для редактирования нескольких разных коллекций.
Кстати, реализацией ICollectionView никто не заделится, часом? Если, кто-то, конечно, занимался кастомной имплементацией...
Собственно, весь этот код используется для динамической генерации чекбоксов на форме.
Далее, мне необходимо при инициализации формы не только вывести список чекбоксов, но и для каждого чекбокса указать его начальное состояние, checked он или unchecked, для чего забиндить ItemsControl.IsChecked на что-то:
Как именно хранить состояние чекбоксов, я волен выбирать сам. Проще всего добавить свойство 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, то соответствующий чекбокс стал бы чекнутым. Я сомневаюсь в своей способности заставить конвертер делать всё это.
Как сделали бы вы?
Здравствуйте, Экселенц, Вы писали:
Э>Как сделали бы вы?
Вариант с 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.
Здравствуйте, MxMsk, Вы писали: MM>Вариант с MyProxyClass.
Спасибо. Да, я согласен, что не обязательно воспроизводить в MyProxyClass все свойства MyClass, можно сделать и как у вас. В принципе мне тоже этот способ кажется достаточно простым и надёжным, но всё же хотелось бы узнать, не существует ли способов обойтись без прокси-класса, а использовать конвертер или какой-то другой механизм. Может кто-нибудь ещё подскажет.