WPF数据表格多选绑定

15

我有一个启用了多选功能的数据网格。我需要在视图模型中更改选择。然而,SelectedItems属性是只读的,无法直接绑定到视图模型中的属性。那么,我该如何向视图发出选择已更改的信号?


请参见https://dev59.com/m0nSa4cB1Zd3GeqPRdaa。 - Colonel Panic
4个回答

18

Andy是正确的。 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;
    }
}

确保在DataGrid元素上设置EnableRowVirtualisation="False",否则会存在选择绑定失效的风险。


太好了。感谢提供示例代码 - 很好地说明了它。 - Mal Ross
谢谢。希望你不介意我在你的示例中添加 EnableRowVirtualisation="False",因为如果没有它,会出现绑定不在新行上的错误。 - Colonel Panic

6
我对于DataGrid的使用不是很熟悉,但是一个适用于ListView的技巧是绑定到单个ListViewItemIsSelected属性。只需将每个对象的该属性设置为true,那么它就会被选中。
也许代表DataGrid行的对象也有一个IsSelected属性,可以这样使用吗?

3

各位,感谢您的帮助。我的问题已经解决了。我认为这个问题对于新的WPF开发人员来说是非常普遍的,因此我会在这里重新阐述我的问题以及解决方案的更多细节,以防其他人遇到类似的问题。

问题:我有一个启用了多选的音频文件数据网格。该网格有多个列标题。用户可以多选几行。当他点击播放按钮时,音频文件将按照一个列标题(比如列A)的顺序播放。当播放开始时,多选将被清除,并且只会突出显示当前正在播放的文件。当所有文件的播放完成后,多选将重新显示。播放是在视图模型中完成的。正如您所看到的,这里有两个问题:1)如何从视图模型中选择当前正在播放的文件,2)如何向视图发送信号,表示播放已完成并重新显示多选。

解决方案:为了解决第一个问题,我在视图模型中创建了一个属性,该属性绑定到视图的SelectedIndex属性以选择当前正在播放的文件。为了解决第二个问题,我在视图模型中创建了一个布尔属性,指示播放已完成。在视图的代码后台中,我订阅了布尔属性的PropertyChanged事件。在事件处理程序中,从保存的多选(在播放开始时,将SelectedItems的内容保存到列表中,并清除SelectedItems)重新创建了视图的SelectedItems属性。起初,我在重新创建SelectedItems时遇到了麻烦。原来问题是由于重新创建是通过第二个线程启动的。WPF不允许这样做。解决此问题的方法是使用Dispatcher.Invoke()让主线程完成工作。对于经验丰富的开发人员来说,这可能是一个非常简单的问题,但对于新手来说,它是一个小挑战。无论如何,感谢不同人士的帮助。


2
只需在任何MultiSelector派生类上使用SelectedItems,并使用它返回的IList上的Add、Remove、Clear方法即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接