简体   繁体   中英

How to set selected items in MVVM using SelectionMode=“Extended”?

Goal

I currently have an app that select the items only by selecting the check box. Like so:

在此处输入图片说明

My goal is to multi select items (Which highlights the selected rows), right click and have a data context menu item to select, selected items.

Desired Output

As an example, this would be my desired output (Obviously not selecting the checkboxes manually).

在此处输入图片说明

Question

What would a good starting point to achieve this output? I couldn't find any examples.

Code

The Model is pretty simple.

public class OrdersModel : BaseVM
{
    public int OrderId { get; set; } // Hidden
    public string OrderNumber { get; set; }
    public DateTime OrderDate { get; set; }
    private bool _selectedRecord;
    public bool SelectedRecord
    {
        get { return _selectedRecord; }
        set
        {
            _selectedRecord = value;
            OnPropertyChanged();
        }
    }
}

And this is my current XAML.

<DataGrid ItemsSource="{Binding Orders}"
          AutoGenerateColumns="False"
          SelectionMode="Extended"
          CanUserAddRows="False">
    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=SelectedRecord}" Value="True">
                    <Setter Property="Background" Value="LightGray" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.RowStyle>
    
    <!--Columns Used-->
    <DataGrid.Columns>

        <!--Select All Column-->
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.HeaderTemplate>
                <DataTemplate>
                    <CheckBox Content="Select All"
                              IsChecked="{Binding DataContext.SelectAll, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}"
                              Command="{Binding DataContext.ToggleAllOrdersCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}"/>
                </DataTemplate>
            </DataGridTemplateColumn.HeaderTemplate>

            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding Path=SelectedRecord, UpdateSourceTrigger=PropertyChanged}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

        <DataGridTextColumn Header="Order Date"
                            Binding="{Binding OrderDate, StringFormat='{}{0:MM-dd-yyyy}'}" Width="*"
                            IsReadOnly="True"
                            FontSize="14" />
        <DataGridTextColumn Header="Order Number"
                            Binding="{Binding OrderNumber}" Width="*"
                            IsReadOnly="True"
                            FontSize="14" />
    </DataGrid.Columns>

    <!--Menu Options-->
    <DataGrid.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Select Highlighted Rows" />
        </ContextMenu>
    </DataGrid.ContextMenu>
</DataGrid>

This solution worked for me. I took the liberty of changing some of your property names to avoid confusion as to what is "selected" and what is "checked".

OrdersModel:

public class OrdersModel : BaseVM
{
    public int OrderId { get; set; } // Hidden
    public string OrderNumber { get; set; }
    public DateTime OrderDate { get; set; }
    private bool _selected;
    private bool _checked;
    public bool Selected
    {
        get { return _selected; }
        set { _selected = value; OnPropertyChanged(); }
    }
    public bool Checked
    {
        get { return _checked; }
        set { _checked = value; OnPropertyChanged(); }
    }
}

MainWindow.xaml.cs

<DataGrid ItemsSource="{Binding Orders}"
  AutoGenerateColumns="False"
  SelectionMode="Extended"
  CanUserAddRows="False"
  Tag="{Binding ElementName=myWindow,Path=DataContext}"
          >
    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow">
            <Setter Property="IsSelected" Value="{Binding Selected}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Selected}" Value="True">
                    <Setter Property="Background" Value="LightGray" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.RowStyle>

    <!--Columns Used-->
    <DataGrid.Columns>

        <!--Select All Column-->
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.HeaderTemplate>
                <DataTemplate>
                    <CheckBox Content="Select All"
                      IsChecked="{Binding DataContext.SelectAll, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}"
                      Command="{Binding DataContext.ToggleAllOrdersCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}"/>
                </DataTemplate>
            </DataGridTemplateColumn.HeaderTemplate>

            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding Path=Checked, UpdateSourceTrigger=PropertyChanged}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

        <DataGridTextColumn Header="Order Date"
                    Binding="{Binding OrderDate, StringFormat='{}{0:MM-dd-yyyy}'}" Width="*"
                    IsReadOnly="True"
                    FontSize="14" />
        <DataGridTextColumn Header="Order Number"
                    Binding="{Binding OrderNumber}" Width="*"
                    IsReadOnly="True"
                    FontSize="14" />
    </DataGrid.Columns>

    <!--Menu Options-->
    <DataGrid.ContextMenu>
        <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
            <MenuItem Header="Select Highlighted Rows" Command="{Binding CheckSelectedCommand}"/>
        </ContextMenu>
    </DataGrid.ContextMenu>
</DataGrid>

MainWindow.xaml.cs:

public class MainWindowViewModel : BaseVM
{
    private ObservableCollection<OrdersModel> _orders;
    private RelayCommand _checkSelectedCommand;

    public MainWindowViewModel()
    {
        Initialize();
    }

    public ObservableCollection<OrdersModel> Orders
    {
        get
        {
            if (_orders == null)
                _orders = new ObservableCollection<OrdersModel>();
            return _orders;
        }
    }

    public RelayCommand CheckSelectedCommand
    {
        get
        {
            if (_checkSelectedCommand == null)
                _checkSelectedCommand = new RelayCommand(o => DoCheckSelectedRows());
            return _checkSelectedCommand;
        }
    }

    public void Initialize()
    {
        var dateTime = DateTime.Now.AddDays(-5);
        for (int i = 0; i < 10; i++)
        {
            this.Orders.Add(new OrdersModel() { OrderId = i, OrderDate = dateTime.AddHours(4), OrderNumber = $"CA{i + 1593:0000}" });
        }
    }

    private void DoCheckSelectedRows()
    {
        var selectedOrders = this.Orders.Where(o => o.Selected);
        foreach (var order in selectedOrders)
        {
            order.Checked = true;
        }
    }
}

Solution will look like this:

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM