WPF DataGrid многоселективная привязка

У меня есть datagrid, который включен в multi-select. Мне нужно изменить выбор в viewmodel. Однако свойство SelectedItems доступно только для чтения и не может быть напрямую привязано к свойству в viewmodel. Итак, как мне передать вид, что выбор изменился?

Ответ 1

Энди прав. DataGridRow.IsSelected - свойство зависимостей, которое может быть привязано к базе данных для управления выбором из ViewModel. Следующий пример кода демонстрирует это:

<Window x:Class="DataGridMultiSelectSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:tk="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <tk:DataGrid AutoGenerateColumns="False" ItemsSource="{Binding}" EnableRowVirtualization="False">
            <tk:DataGrid.Columns>
                <tk:DataGridTextColumn Header="Value" Binding="{Binding Value}" />
            </tk:DataGrid.Columns>
            <tk:DataGrid.RowStyle>
                <Style TargetType="tk:DataGridRow">
                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                </Style>
            </tk:DataGrid.RowStyle>
        </tk:DataGrid>
        <Button Content="Select Even" Click="Even_Click" />
        <Button Content="Select Odd" Click="Odd_Click" />
    </StackPanel>
</Window>

using System.ComponentModel;
using System.Windows;

namespace DataGridMultiSelectSample
{
    public partial class Window1
    {
        public Window1()
        {
            InitializeComponent();
            DataContext = new[]
                              {
                                  new MyViewModel {Value = "Able"},
                                  new MyViewModel {Value = "Baker"},
                                  new MyViewModel {Value = "Charlie"},
                                  new MyViewModel {Value = "Dog"},
                                  new MyViewModel {Value = "Fox"},
                              };
        }

        private void Even_Click(object sender, RoutedEventArgs e)
        {
            var array = (MyViewModel[]) DataContext;
            for (int i = 0; i < array.Length; ++i)
                array[i].IsSelected = i%2 == 0;
        }

        private void Odd_Click(object sender, RoutedEventArgs e)
        {
            var array = (MyViewModel[])DataContext;
            for (int i = 0; i < array.Length; ++i)
                array[i].IsSelected = i % 2 == 1;
        }
    }

    public class MyViewModel : INotifyPropertyChanged
    {
        public string Value { get; set; }

        private bool mIsSelected;
        public bool IsSelected
        {
            get { return mIsSelected; }
            set
            {
                if (mIsSelected == value) return;
                mIsSelected = value;
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("IsSelected"));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

Обязательно установите EnableRowVirtualisation="False" в элементе DataGrid, иначе существует риск того, что привязки IsSelected выпадут из очереди.

Ответ 2

Я не работал с DataGrid много, но один метод, который работает для ListView, - это привязка к свойству IsSelected для отдельного ListViewItem. Просто установите для этого параметра значение true для каждого объекта в вашем списке, а затем он будет выбран.

Может быть, объект, представляющий строку в DataGrid, также имеет свойство IsSelected и может также использоваться таким образом?

Ответ 3

Ребята, спасибо за помощь. Моя проблема решена. Я думаю, что эта проблема довольно распространена для новых разработчиков WPF, поэтому я буду более подробно останавливать свою проблему, а также решение более подробно здесь, на случай, если кто-то другой столкнется с такими же проблемами.

Проблема: у меня есть многоэкранный включенный datagrid аудиофайлов. Сетка имеет несколько заголовков столбцов. Пользователь может многократно выбирать несколько строк. Когда он нажимает кнопку "Воспроизведение", звуковые файлы будут воспроизводиться в порядке очереди заголовков столбцов (скажем, столбец A). Когда воспроизведение начинается, мультивыбор очищается, и выделяется только текущий воспроизводимый файл. Когда воспроизведение будет завершено для всех файлов, будет отображен многоэкранный выбор. Воспроизведение выполняется в режиме просмотра. Как вы можете видеть, здесь есть две проблемы: 1) как выбрать текущий воспроизводимый файл из режима просмотра и 2) как подать сигнал в представление из режима просмотра, что воспроизведение закончено, и повторно отобразить многоэкранный выбор.

Решение. Чтобы решить первую проблему, я создал свойство в viewmodel, которое связано с представлением свойства SelectedIndex, чтобы выбрать текущий воспроизводимый файл. Чтобы решить вторую проблему, я создал логическое свойство в модели представления, чтобы показать, что воспроизведение закончено. В коде зрения, я подписался на событие boolean propertyChanged. В обработчике события свойство SelectedItems будет восстановлено из сохраненного множественного выбора (содержимое SelectedItems было сохранено в списке, а SelectedItems было очищено при запуске воспроизведения). Сначала у меня возникли проблемы с повторным созданием SelectedItems. Оказалось, что проблема связана с тем, что повторное создание было инициировано через второй поток. WPF этого не допускает. Решение этого - использовать Dispatcher.Invoke(), чтобы основной поток выполнял работу. Это может быть очень простой проблемой для опытных разработчиков, но для новичков это небольшая проблема. Во всяком случае, много помощи от разных людей.

Ответ 4

Просто используйте SelectedItems для любого производного класса MultiSelector и используйте методы Add, Remove, Clear on IList, которые он возвращает.

С уважением, Робин