WPF DataGrid многоселевое связывание - PullRequest
14 голосов
/ 11 апреля 2010

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

Ответы [ 4 ]

17 голосов
/ 11 апреля 2010

Энди прав. 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 выпадут из строя.

6 голосов
/ 11 апреля 2010

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

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

3 голосов
/ 14 апреля 2010

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

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

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

2 голосов
/ 19 июля 2011

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

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

...