0

I have a WPF DataGrid, the ItemsSource property is bound to the viewmodel. On click on a Button a method is doing work on the selected rows of the DataGrid. When the work is done, I would like to unselectAll the DataGrid's rows from the viewmodel, how can I achieve this in a MVVM way?

XAML :

<DataGrid AutoGenerateColumns="False"
     ItemsSource="{Binding ObCol_View}"
     SelectedItem="{Binding SelectedItem}

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <GalaCmd:EventToCommand Command="{Binding SelectionChangedCommand}" CommandParameter="{Binding SelectedItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</DataGrid>

<Button Content="Apply" Command="{Binding PerformCommand}"/>

The viewmodel

public class ViewModelprices_manager<T> : WindowViewModel
{
    public ViewModelprices_manager()
    {
        SelectionChangedCommand = new RelayCommand<IList>
        (items =>
            {
                SelectedItems = items;
            }
        );

        myObCol_View = new ObservableCollection<View_prices_manager<T>>();
    }

    public IList SelectedItems { get; set; }

    private readonly ObservableCollection<View_prices_manager<T>> myObCol_View;
    public ObservableCollection<View_prices_manager<T>> ObCol_View_Parametric { get { return myObCol_View; } }

    public RelayCommand<IList> SelectionChangedCommand
    {
        get;
        private set;
    }

    private RelayCommand myPerformCommand;

    public RelayCommand PerformCommand
    {
        get
        {
            if (myPerformCommand == null)
                myPerformCommand = new RelayCommand(PerformCommandAction);

            return myPerformCommand;
        }
    }

    private void PerformCommandAction()
    {
        perform();
    }

    public void perform()
    {
        foreach (View_prices_manager<T> item in SelectedItems)
        {
            item.Price *= ratio;
        }

        //DataGrid.UnselectAll <-- Here I want to unselect all to reset the selection in SelectedItems
    }
}
Chris Schaller
  • 13,704
  • 3
  • 43
  • 81
Yannick
  • 194
  • 8
  • You are using the SelectedItems list. In this property you have a link to DataGrid.SelectedItems. After processing, you just need to clear this list `SelectedItems.Clear()`. Also, in my opinion, your implementation of the SelectionChangedCommand is not entirely correct. Its only function is to get the SelectedItems list. But this list does not change in the DataGrid. Only the elements in it are changed (added, removed). Therefore, it is enough to popup this list once after initialization (or loading) of the DataGrid. – EldHasp May 19 '21 at 12:36
  • The reason of this implementation is that the SelectedItems property is a readonly property. This implementation allow me to get the selecteditems even if the EnableRowVirtualization property is enabled. One can do it with a behavior as well. So SelectedItems.Clear() will has no effect on DataGrid selection. – Yannick May 19 '21 at 16:16
  • I see, you are right! I have misunderstood indeed. Pity that this topic is closed. – Yannick May 19 '21 at 19:11
  • Add clarifying details to the question and ask to open it. Or create a new theme, but not a duplicate, but with all the specifying details, including the implementation of all custom types (in a simplified form). So that others can copy your code into their project and run it. – EldHasp May 20 '21 at 07:51
  • The topic is reopened, I would like to see your solution, many Thanks! – Yannick May 20 '21 at 09:25

2 Answers2

1

To clear the selection the MVVM way.

Bind to the SelectedItem property to the view model:

<DataGrid SelectedItem="{Binding SelectedItem, Mode=TwoWay}">

And set the SelectItem to null in your code:

viewModel.SelectItem = null;

Of course, your viewModel class must implement INotifyPropertyChanged properly.

Orace
  • 7,822
  • 30
  • 45
  • Yes, it works thanks! An idea about sellectAll from the viewmodel? – Yannick May 17 '21 at 17:35
  • I don't see a way to do it with the current `DataGrid` implementation. Maybe an `AreAllItemSelected` attached property can do the trick. – Orace May 17 '21 at 17:42
1

The topic is reopened, I would like to see your solution

A simplified example.
If you need any additional details, then write which ones and I will add or explain them.

The example uses the BaseInpc and RelayCommand classes.

Collection item class:

using Simplified;

namespace ClearSelectedItems
{
    public class Product : BaseInpc
    {
        private string _title;
        private decimal _price;

        public string Title { get => _title; set => Set(ref _title, value); }
        public decimal Price { get => _price; set => Set(ref _price, value); }
    }
}

ViewModel:

using Simplified;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;

namespace ClearSelectedItems
{
    public class ProductsViewModel
    {
        public IList SelectedProducts{ get; set; }

        public decimal Ratio { get; set; }

        private ICommand _performCommand;
        public ICommand PerformCommand => _performCommand
            ?? (_performCommand = new RelayCommand(PerformExecute));

        private void PerformExecute(object parameter)
        {
            foreach (var product in SelectedProducts.Cast<Product>())
            {
                product.Price *= Ratio;
            }

            // Clearing selection
            SelectedProducts.Clear();
        }

        // An example of filling a collection
        public List<Product> Products { get; }
            = new List<Product>()
            {
                new Product() { Title = "IPhone", Price=1500},
                new Product() { Title = "Samsung", Price=1200},
                new Product() { Title = "Nokia", Price=1000},
                new Product() { Title = "LG", Price=500}
           };
    }
}

Class of static handlers. Used for simplicity, so as not to create Behavior.

using System;
using System.Windows.Controls.Primitives;

namespace ClearSelectedItems
{
    public static class Handlers
    {
        public static EventHandler OnDataGridInitialized { get; } = (sender, e) =>
        {
            MultiSelector selector = (MultiSelector)sender;
            ProductsViewModel viewModel = (ProductsViewModel)selector.DataContext;
            viewModel.SelectedProducts = selector.SelectedItems;
        };
    }
}

Window XAML:

<Window x:Class="ClearSelectedItems.ExampleWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ClearSelectedItems"
        mc:Ignorable="d"
        Title="ExampleWindow" Height="450" Width="400">
    <Window.DataContext>
        <local:ProductsViewModel/>
    </Window.DataContext>
    <Grid>
        <DataGrid ItemsSource="{Binding Products}"
                  Initialized="{x:Static local:Handlers.OnDataGridInitialized}"/>
        
        <TextBox Text="{Binding Ratio}" VerticalAlignment="Bottom" HorizontalAlignment="Left" 
                 MinWidth="100" Margin="5" Padding="15 5"/>
        
        <Button Content="Apply Ratio" Command="{Binding PerformCommand}"
                Margin="5" Padding="15 5"
                HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
    </Grid>
</Window>
EldHasp
  • 6,079
  • 2
  • 9
  • 24