Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataGrid WPF Virtualization and Command CanExecute

I'm working on a WPF application with framework .NET 4.0

I have a problem with a DataGrid : every line got 2 commands :

public ICommand MoveUpOrderPipeCommand
{
     get
     {
         if (_moveUpOrderPipeCommand == null)
         {
              _moveUpOrderPipeCommand = new Command<OrderPipeListUIModel>(OnMoveUpOrderPipe, CanMoveUpOrderPipe);
         }
                return _moveUpOrderPipeCommand;
      }
}

private bool CanMoveUpOrderPipe(OrderPipeListUIModel orderPipe)
{
     if (OrderPipes == null || !OrderPipes.Any() || OrderPipes.First() == orderPipe)
          return false;
     return true;
}

And there is the same command for MoveDown (Can execute check if the line is not the last one)

And the DataGrid :

<DataGrid Grid.Row="1" IsReadOnly="True" ItemsSource="{Binding OrderPipes}" SelectionMode="Extended">
   <DataGrid.Columns>
      <DataGridTextColumn Header="Diam. (mm)" Binding="{Binding Diameter}" Width="120">    </DataGridTextColumn>
      <DataGridTextColumn Header="Lg. (m)" Binding="{Binding Length}" Width="120"></DataGridTextColumn>
      <DataGridTextColumn Header="Ep. (mm)" Binding="{Binding Thickness}" Width="120"></DataGridTextColumn>
      <DataGridTextColumn Header="Ondulation" Binding="{Binding Ripple}" Width="120"></DataGridTextColumn>
      <DataGridTemplateColumn>
         <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
               <StackPanel Orientation="Horizontal">
                  <Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.MoveUpOrderPipeCommand}" CommandParameter="{Binding}">
                  </Button>
               </StackPanel>
            </DataTemplate>
         </DataGridTemplateColumn.CellTemplate>
      </DataGridTemplateColumn>
   </DataGrid.Columns>
</DataGrid>

If i virtualize my grid with EnableRowVirtualization to true, i have some trouble, if i scroll to the bottom (first lines not visible anymore) and then scroll back to top, sometimes the button moveup of the first line (normaly can't move up) is enable until i click on the DataGrid, and also the second or the third one is disable, should be enable!

If i set EnableRowVirtualization to false, i don't have this problem...

I only found one other post on the internet that talk about this problem, but there is not the dataGrid from .net framework : http://www.infragistics.com/community/forums/t/15189.aspx

Do you have any idea how can I fix it?

Thank you in advance

Edit : The command class

public class Command<T> : ICommand
{
    private readonly Action<T> _execute;
    private readonly Func<T, bool> _canExecute;

    public Command(Action<T> execute) : this(execute, null)
    {
    }

    public Command(Action<T> execute, Func<T, bool> canExecute)
    {
       if (execute == null)
          throw new ArgumentNullException("execute", "Le délégué execute ne peut pas être nul");

       this._execute = execute;
       this._canExecute = canExecute;
    }

    public event EventHandler CanExecuteChanged
    {
       add
       {
          CommandManager.RequerySuggested += value;
       }
       remove
       {
          CommandManager.RequerySuggested -= value;
       }
    }

    public bool CanExecute(object parameter)
    {
       return (_canExecute == null) ? true : _canExecute((T)parameter);
    }

    public void Execute(object parameter)
    {
       _execute((T)parameter);
    }
 }
like image 394
Tan Avatar asked Nov 14 '13 15:11

Tan


1 Answers

The problem is when you scroll with the mouse wheel, the canExecute is not called.

I create a AttachedProperty to correct this, and it could be use in a style.

public static readonly DependencyProperty CommandRefreshOnScrollingProperty = DependencyProperty.RegisterAttached(
            "CommandRefreshOnScrolling", 
            typeof(bool), 
            typeof(DataGridProperties), 
            new FrameworkPropertyMetadata(false, OnCommandRefreshOnScrollingChanged));

private static void OnCommandRefreshOnScrollingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
      var dataGrid = d as DataGrid;
      if (dataGrid == null)
      {
          return;
      }
      if ((bool)e.NewValue)
      {
         dataGrid.PreviewMouseWheel += DataGridPreviewMouseWheel;
      }
}
private static void DataGridPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
     CommandManager.InvalidateRequerySuggested();
}

And you can use this attachedProperty in a style like this:

    <Setter Property="views:DataGridProperties.CommandRefreshOnScrolling" Value="True"></Setter>

Thanks Eran Otzap to show me why i got this problem!

like image 127
Tan Avatar answered Oct 29 '22 16:10

Tan