MVVM - WPF DataGrid - Событие AutoGeneratingColumn

В настоящее время я внимательно изучаю отличный инструментарий Лорана, и у меня возник следующий вопрос.

Из Blend 4 я добавил EventTrigger для события Loaded, в моей ViewModel у меня есть следующее:

public RelayCommand rcAutoGeneratingColumn { get; private set; }

В конструкторе у меня есть:

rcAutoGeneratingColumn = 
   new RelayCommand(o => DataGridAutoGeneratingColumn(o));

Также в ViewModel у меня есть метод, который я хочу вызвать RelayCommand:

    private void DataGridAutoGeneratingColumn(Object o)
    {
        DataGrid grid = (DataGrid)o;

        foreach (DataGridTextColumn col in grid.Columns)
        {
            if (col.Header.ToString().ToLower() == "id")
            {
                col.Visibility = System.Windows.Visibility.Hidden;
            }
        }
    }

Мой XAML содержит следующее (для DataGrid):

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <GalaSoft_MvvmLight_Command:EventToCommand 
            Command="{Binding rcAutoGeneratingColumn, Mode=OneWay}"
            CommandParameter="{Binding ElementName=dataGrid1, Mode=OneWay}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

Здесь НЕТ ПРОБЛЕМЫ, код работает нормально, но очевидно, что событие, используемое для скрытия определенных столбцов, должно быть событием AutoGeneratingColumn, а не загружено. Я использовал событие Loaded в качестве обходного пути.

Я надеялся, что смогу ретранслировать любое событие, предлагаемое элементом управления, чтобы в этом случае вместо этого работало следующее:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="AutoGeneratingColumn">
        <GalaSoft_MvvmLight_Command:EventToCommand 
            Command="{Binding rcAutoGeneratingColumn, Mode=OneWay}"
            CommandParameter="{Binding ElementName=dataGrid1, Mode=OneWay}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

Я не могу вызвать событие AutoGeneratingColumn, и я надеюсь, что я что-то упустил, и ценю любой предоставленный совет!

Это поведение аналогично GridControl от DevExpress, в котором событие Loaded запускается, а событие ColumnsPopulated (эквивалентно событию AutoGeneratingColumn) - нет.

DevExpress предоставил следующую информацию по моему вопросу:

«Мы рассмотрели этот вопрос и пришли к интересному выводу. Похоже, что визуальное дерево не строится в тот момент, когда обрабатываются триггеры Interaction.Trigger»

Если это правда, и нет другого способа вызвать события в ViewModel, тогда нужно будет пойти дальше и - методом проб и ошибок - отметить, какие из событий DataGrid (из которых более 100) можно вызывать таким образом, а чего нельзя!

Хотелось бы думать, что каждое событие, которое доступно в коде программной части, также может быть достигнуто при применении шаблона MVVM.

Я искал ответ, но не могу исключить, что что-то упустил, поэтому, если это так, примите мои извинения!


person Dave    schedule 07.10.2010    source источник


Ответы (3)


В ходе разработки проекта с помощью MVVM у вас могут возникнуть обстоятельства, когда вы должны обрабатывать события в коде программной части вашего представления, а EventToCommand просто не работает. Вы особенно находите это в Silverlight, но из вашего вопроса я предполагаю, что вы используете WPF. Это нормально - выполнять некоторую обработку событий в коде программной части вашего представления, только не добавляйте туда никакой бизнес-логики. Вы даже можете оставить команду в своей модели представления, просто вызовите ее прямо из обработчика событий.

((YourViewModel)this.DataContext).rcAutoGeneratingColumn.Execute(sender);
person Matt Casto    schedule 07.10.2010
comment
Привет, Мэтт, спасибо за комментарии. Я не смог заявить, что действительно имел в виду WPF, но вы выбрали его. Я должен признать, что считал недопустимым иметь обработку событий в коде, поэтому приятно слышать обратное. Бизнес-логика здесь, конечно, не соблюдается. Мне также нравится ваше предложение кода! Спасибо за помощь этому новичку :) - person Dave; 11.10.2010

Вам не нужно использовать злой код ;-) Вы можете сделать это, используя прикрепленное поведение ...

public class AutoGeneratingColumnEventToCommandBehaviour
{
    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached(
            "Command", 
            typeof(ICommand), 
            typeof(AutoGeneratingColumnEventToCommandBehaviour),
            new PropertyMetadata(
                null,
                CommandPropertyChanged));

    public static void SetCommand(DependencyObject o, ICommand value)
    {
        o.SetValue(CommandProperty, value);
    }

    public static ICommand GetCommand(DependencyObject o)
    {
        return o.GetValue(CommandProperty) as ICommand;
    }

    private static void CommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var dataGrid = d as DataGrid;
        if (dataGrid != null)
        {
            if (e.OldValue != null)
            {
                dataGrid.AutoGeneratingColumn -= OnAutoGeneratingColumn;
            }
            if (e.NewValue != null)
            {
                dataGrid.AutoGeneratingColumn += OnAutoGeneratingColumn;
            }
        }
    }

    private static void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        var dependencyObject = sender as DependencyObject;
        if (dependencyObject != null)
        {
            var command = dependencyObject.GetValue(CommandProperty) as ICommand;
            if (command != null && command.CanExecute(e))
            {
                command.Execute(e);
            }
        }
    }
}

Затем используйте его в XAML вот так ...

<DataGrid ItemsSource="{Binding MyGridSource}"
          AttachedCommand:AutoGeneratingColumnEventToCommandBehaviour.Command="{Binding CreateColumnsCommand}">
</DataGrid>
person Russell Giddings    schedule 09.04.2013
comment
У меня есть время, чтобы понять, как использовать и что такое CreateColumnsCommand, но, наконец, я понял, что это метод режима просмотра с параметром DataGridAutoGeneratingColumnEventArgs. Работает как шарм, спасибо! - person Mardok; 18.11.2015

Просто установите свойство EventTrigger.SourceObject.

<DataGrid
  x:Name="DataGrid"
  AutoGenerateColumns="True"
  IsReadOnly="True"
  ItemsSource="{Binding Data}">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="AutoGeneratingColumn" SourceObject="{Binding ElementName=DataGrid}">
      <local:EventToCommand
        Command="{Binding ColumnGeneratingCommand}"
        PassEventArgsToCommand="True" />
    </i:EventTrigger>
  </i:Interaction.Triggers>
</DataGrid>
person user11354240    schedule 13.04.2019