MVVM - WPF DataGrid - AutoGeneratingColumn事件

时间:2010-10-07 13:03:31

标签: wpf mvvm datagrid devexpress mvvm-light

我目前正在审视Laurent的优秀工具包,我有以下问题。

在Blend 4中,我为Loaded事件添加了一个EventTrigger,在我的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。 我曾经习惯将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事件,我希望我忽略了一些事情并感谢任何建议!

此行为与DevExpress中的GridControl相同,因为Loaded事件被触发而 ColumnsPopulated 事件(这相当于AutoGeneratingColumn事件)不是。

DevExpress就我的问题提供了以下信息:

我们已经回顾了这个问题,得出了一个有趣的结论。看起来,当处理Interaction.Triggers时,可视化树还没有被构建

如果这是真的,并且没有其他方法可以调用ViewModel中的事件,那么就必须继续 - 通过使用试验和错误 - 注意哪些DataGrid事件(其中有哪些)超过100)可以这种方式调用,哪些不能!

人们可能会认为在应用MVVM模式时也可以访问代码隐藏中可用的每个事件。

我已经找到了答案,但我不能排除我忽略了某些事情,所以如果是这样的话,请接受我的道歉!

3 个答案:

答案 0 :(得分:12)

您不必使用背后的恶意代码;-)您可以使用附加行为来执行此操作...

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>

答案 1 :(得分:0)

只需设置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>

答案 2 :(得分:-1)

在使用MVVM开发项目的过程中,您将遇到必须处理视图中代码隐藏事件和EventToCommand事件的情况。你特别喜欢Silverlight,但我从你的问题中假设你正在使用WPF。在视图的代码隐藏中做一些事件处理是可以的,只是不要在那里放任何业务逻辑。您甚至可以将命令保留在视图模型中,只需直接从事件处理程序中调用它即可。

((YourViewModel)this.DataContext).rcAutoGeneratingColumn.Execute(sender);