2016-02-22 3 views
1

Я создал свою собственную DataGrid, которая реализует событие RowClick. Однако, пытаясь связать команду с ней, она выкинет исключение:Событие имеет несовместимую подпись - EventHandler <T>

{"В событии \" RowClick \ "типа \" ExtendedDataGrid \ "есть несовместимая подпись. Убедитесь, что событие является общедоступным и удовлетворяет делегату EventHandler. "}

Поскольку я новичок в MVVM, у меня уже болит весь вход, который я получил за последние пару дней в MVVM. Кто-то подсказывает мне (в основном) очевидную ошибку?

Заранее спасибо

Вот мой (TestProject) код:

public class ExtendedDataGrid : DataGrid 
{ 
    public event EventHandler<DataGridRow> RowClick; 

    public ExtendedDataGrid() 
    { 
     this.DefaultStyleKey = typeof(DataGrid); 
    } 

    protected override void PrepareContainerForItemOverride(DependencyObject element, object item) 
    { 
     var row = (DataGridRow)element; 

     row.PreviewKeyDown += RowOnKeyDown; 
     row.MouseLeftButtonUp += RowOnMouseLeftButtonUp; 

     base.PrepareContainerForItemOverride(element, item); 
    } 

    protected override void ClearContainerForItemOverride(DependencyObject element, object item) 
    { 
     var row = (DataGridRow)element; 

     row.KeyUp -= RowOnKeyDown; 
     row.MouseLeftButtonUp -= RowOnMouseLeftButtonUp; 

     base.ClearContainerForItemOverride(element, item); 
    } 

    private void RowOnMouseLeftButtonUp(object sender, MouseButtonEventArgs mouseButtonEventArgs) 
    { 
     mouseButtonEventArgs.Handled = true; 

     this.OnRowClick((DataGridRow)sender); 
    } 

    private void RowOnKeyDown(object sender, KeyEventArgs keyEventArgs) 
    { 
     if (keyEventArgs.Key != Key.Enter) 
      return; 

     keyEventArgs.Handled = true; 

     this.OnRowClick((DataGridRow)sender); 
    } 

    protected virtual void OnRowClick(DataGridRow clickedRow) 
    { 
     if (null == this.RowClick) 
      return; 

     this.RowClick(this, clickedRow); 
    } 
} 

Window.xaml

<controls1:ExtendedDataGrid x:Name="extGrid"> 
     <i:Interaction.Triggers> 
      <i:EventTrigger EventName="RowClick" SourceObject="{Binding ElementName=extGrid}"> 
       <i:InvokeCommandAction Command="{Binding MyCommand}" CommandParameter="{Binding SelectedItem,ElementName=extGrid}" /> 
      </i:EventTrigger> 
     </i:Interaction.Triggers> 
     <controls1:ExtendedDataGrid.Items> 
      <TextBlock Text="Text" /> 
     </controls1:ExtendedDataGrid.Items> 
    </controls1:ExtendedDataGrid> 

window.xaml.cs

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     this.DataContext = this; 
     this._selectCommand = new DelegateCommand<DataGridRow>(x => 
     { 

     }); 

//following works fine.. 
this.extGrid.RowClick += (s, e) => 
     { 

     }; 
    } 

    private DelegateCommand<DataGridRow> _selectCommand; 
    public ICommand MyCommand 
    { 
     get 
     { 
      return this._selectCommand; 
     } 
    } 
} 

DelegateCommand Реализация:

public class DelegateCommand<T> : DelegateCommand 
{ 
    public DelegateCommand(Action<T> executeHandler) 
     : this(null, executeHandler) 
    { } 

    public DelegateCommand(Func<T, bool> canExecuteHandler, Action<T> executeHandler) 
     : base(o => null == canExecuteHandler || canExecuteHandler((T)o), o => executeHandler((T)o)) 
    { 
     if (null == executeHandler) 
      throw new ArgumentNullException("executeHandler"); 
    } 
} 

/// <summary> 
/// Stellt ein standard DelegateCommand dar. 
/// </summary> 
public class DelegateCommand : ICommand 
{ 
    #region Events 

    public event EventHandler CanExecuteChanged; 

    #endregion 

    #region Variablen 

    private readonly Action<object> _executeHandler; 
    private readonly Func<object, bool> _canExecuteHandler; 
    private bool _isExecuting = false; 

    #endregion 

    #region Eigenschaften 

    public bool IsSingleExecution { get; set; } 

    #endregion 

    #region Konstruktor 

    public DelegateCommand(Action<object> executeHandler) 
     : this(null, executeHandler) 
    { } 

    public DelegateCommand(Func<object, bool> canExecuteHandler, Action<object> executeHandler) 
    { 
     if (null == executeHandler) 
      throw new ArgumentNullException("executeHandler"); 

     this._executeHandler = executeHandler; 
     this._canExecuteHandler = canExecuteHandler; 
    } 

    #endregion 

    #region Public Methoden 


    public virtual bool CanExecute(object parameter) 
    { 
     return (!this.IsSingleExecution || (this.IsSingleExecution && !this._isExecuting)) && (null == this._canExecuteHandler || this._canExecuteHandler(parameter)); 
    } 

    public virtual void Execute(object parameter) 
    { 
     if (this.CanExecute(parameter)) 
     { 
      this._isExecuting = true; 
      this.RaiseCanExecuteChanged(); 

      try 
      { 
       this._executeHandler(parameter); 
      } 
      finally 
      { 
       this._isExecuting = false; 
       this.RaiseCanExecuteChanged(); 
      } 
     } 
    } 

    public void RaiseCanExecuteChanged() 
    { 
     if (null != CanExecuteChanged) 
      CanExecuteChanged(this, EventArgs.Empty); 
    } 

    #endregion 
+0

Событие должно быть RoutedEvent, Держу пари. – Will

ответ

3

Проблема исходит от этой линии:

<i:EventTrigger EventName="RowClick" SourceObject="{Binding ElementName=extGrid}"> 

EventTrigger класса ожидает маршрутизированное событие, которое использует RoutedEventHandler делегата а не EventHandler делегата.

Эти изменения, которые необходимо внести в своем коде, чтобы сделать его работу:

В ExtendedDataGrid:

public class ExtendedDataGrid : DataGrid 
{ 
    public static readonly RoutedEvent RowClickEvent = EventManager.RegisterRoutedEvent("RowClick", 
      RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ExtendedDataGrid)); 

    public event RoutedEventHandler RowClick 
    { 
     add { AddHandler(RowClickEvent, value); } 
     remove { RemoveHandler(RowClickEvent, value); } 
    } 

    public ExtendedDataGrid() 
    { 
     this.DefaultStyleKey = typeof(DataGrid); 
    } 

    protected override void PrepareContainerForItemOverride(DependencyObject element, object item) 
    { 
     var row = (DataGridRow)element; 

     row.PreviewKeyDown += RowOnKeyDown; 
     row.MouseLeftButtonUp += RowOnMouseLeftButtonUp; 

     base.PrepareContainerForItemOverride(element, item); 
    } 

    protected override void ClearContainerForItemOverride(DependencyObject element, object item) 
    { 
     var row = (DataGridRow)element; 

     row.KeyUp -= RowOnKeyDown; 
     row.MouseLeftButtonUp -= RowOnMouseLeftButtonUp; 

     base.ClearContainerForItemOverride(element, item); 
    } 

    private void RowOnMouseLeftButtonUp(object sender, MouseButtonEventArgs mouseButtonEventArgs) 
    { 
     mouseButtonEventArgs.Handled = true; 

     this.OnRowClick((DataGridRow)sender); 
    } 

    private void RowOnKeyDown(object sender, KeyEventArgs keyEventArgs) 
    { 
     if (keyEventArgs.Key != Key.Enter) 
      return; 

     keyEventArgs.Handled = true; 

     this.OnRowClick((DataGridRow)sender); 
    } 

    protected virtual void OnRowClick(DataGridRow clickedRow) 
    { 
     var args = new RowClickRoutedEventArgs(clickedRow); 
     args.RoutedEvent = RowClickEvent; 
     RaiseEvent(args); 
    } 
} 

Здесь я удалил предыдущую RowClick события и изменил метод OnRowClick.

Добавить новый класс RowClickRoutedEventArgs:

public class RowClickRoutedEventArgs : RoutedEventArgs 
{ 
    public RowClickRoutedEventArgs(DataGridRow dataGridRow) 
    { 
     Row = dataGridRow; 
    } 

    public DataGridRow Row { get; set; } 
} 
+0

Это была ошибка - Спасибо! – user1021605