AymenDaoudi
AymenDaoudi

Reputation: 8301

Bound-to DataGrid's SelectedItems not Notifying Target

I am binding the IsEnabled Property of a Button to the number of SelectedItems of a DataGrid.

XAML :

<DataGrid SelectionChanged="DG_Reports_OnSelectionChanged" x:Name="DG_Reports" SelectionMode="Extended" ItemsSource="{Binding Reportslists, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=Explicit}" AutoGenerateColumns="False" CanUserAddRows="True" CanUserReorderColumns="False" CanUserDeleteRows="True">
        <DataGrid.RowHeaderTemplate>
              <DataTemplate>
                   <Grid>
                         <CheckBox IsChecked="{Binding Path=IsSelected, Mode=TwoWay,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type DataGridRow}}}"/>
                   </Grid>
              </DataTemplate>
        </DataGrid.RowHeaderTemplate>            
        <DataGrid.Columns>
             <!-- Columns Here -->
        </DataGrid.Columns>
</DataGrid>

<Button x:Name="Bt_RemoveReports" Content="Supprimer Rapport" IsEnabled="{Binding ElementName=DG_Reports, NotifyOnSourceUpdated=True, Path=SelectedItems, Converter={StaticResource SelectedDataGridRowsToBooleanConverter}}">
        <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                      <command:EventToCommand Command="{Binding DeleteReports}" CommandParameter="{Binding ElementName=DG_Reports, Path=SelectedItems}"/>
                </i:EventTrigger>
        </i:Interaction.Triggers>
</Button>

The SelectedDataGridRowsToBooleanConverter Converter :

public class SelectedDataGridRowsToBooleanConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((IList<Object>) value).Count > 0;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

In the beginning (Means when nothing is selected in the DataGrid) the Button is successfully Not Enabled, but once I start selecting rows, nothing happens, I should note that the DataGrid's SelectionChanged event fires normally, but the button is never notified of the changing in selection, what may I be missing here ?

Upvotes: 1

Views: 349

Answers (1)

Ayyappan Subramanian
Ayyappan Subramanian

Reputation: 5366

For DataGrid SelectedItems is a collection and cannot be used like above. Instead you can use SelectedItems.Count and change the converter as mentioned below.

 <Button x:Name="Bt_RemoveReports" Content="Supprimer Rapport" IsEnabled="{Binding ElementName=DG_Reports, 
        NotifyOnSourceUpdated=True, Path=SelectedItems.Count, Converter={StaticResource SelectedDataGridRowsToBooleanConverter}}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
                <command:EventToCommand Command="{Binding DeleteReports}" CommandParameter="{Binding ElementName=DG_Reports, Path=SelectedItems}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>
public class SelectedDataGridRowsToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (int)value > 0;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Other way of achieve this functionality. In this you need to write converter. Command's CanExecute method with take of enabling and Disabling of the button. You need not to use Interaction triggers for buttons since it already has Command property associated to click event. Refer below code.

 <StackPanel>        
    <DataGrid x:Name="DG_Reports" Height="200"
            AutoGenerateColumns="False"                
            ItemsSource="{Binding SampleItems}" >
        <DataGrid.RowHeaderTemplate>
            <DataTemplate>
                <Grid>
                    <CheckBox IsChecked="{Binding Path=IsSelected, Mode=TwoWay,
                        RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type DataGridRow}}}"/>
                </Grid>
            </DataTemplate>
        </DataGrid.RowHeaderTemplate>
        <DataGrid.Columns>
            <DataGridTextColumn Header="Date" Binding="{Binding DayOfMonth}">                   
            </DataGridTextColumn>
            <DataGridTextColumn Header="Day" Binding="{Binding Weekday}">                    
            </DataGridTextColumn>
        </DataGrid.Columns>
    </DataGrid>
    <Button x:Name="Bt_RemoveReports" Content="Supprimer Rapport" Command="{Binding DeleteReports}"
            CommandParameter="{Binding ElementName=DG_Reports, Path=SelectedItems}">            
    </Button>
</StackPanel>   

 public class Item
{
    public int DayOfMonth { get; set; }
    public string Weekday { get; set; }
}

public class MainViewModel 
{
    private ObservableCollection<Item> m_items;
    public ObservableCollection<Item> SampleItems
    {
        get { return m_items; }
        set { m_items=value; }
    }

    public ICommand DeleteReports { get; private set; }

    public MainViewModel()
    {
        DeleteReports = new RelayCommand<object>(Delete,CanDelete);

        var items = new ObservableCollection<Item>();
        var today = DateTime.Now;
        for (int i = 1; i <= DateTime.DaysInMonth(today.Year, today.Month); i++)
        {
            items.Add(new Item { DayOfMonth = i, Weekday = new DateTime(today.Year, today.Month, i).DayOfWeek.ToString() });
        }
        SampleItems = items;
    }

    private void Delete(object obj)
    {
        var items = new ObservableCollection<Item>();
        foreach (var item in (IList)obj)
        {
            items.Add((Item)item);
        }
        foreach (var item in items)
        {
            m_items.Remove(item);
        }
    }

    private bool CanDelete(object obj)
    {
        return ((IList)obj).Count > 0;
    }

}

Upvotes: 1

Related Questions