MVVM - WPF数据网格-自动生成列事件

lndjwyie  于 2022-11-18  发布在  其他
关注(0)|答案(4)|浏览(139)

我目前正在仔细研究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包含以下内容(对于数据网格):

<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事件用作getaround。

我希望可以中继控件提供的任何事件,这样,在本例中,以下代码将起作用:

<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就我的问题提供了以下信息:

  • 我们已经检查了此问题,并得出了一个有趣得结论.看起来在处理交互.触发器时没有生成可视化树 *

如果这是真的,并且没有其他方法来调用ViewModel中的事件,那么就必须继续进行-通过反复试验-注意哪些DataGrid事件(有100多个)可以用这种方法调用,哪些不能!
人们会认为代码隐藏中可用的每个事件在应用MVVM模式时也可以到达。
我一直在寻找一个答案,但我不能排除我忽略了一些东西,所以如果是这样的话,那么请接受我的道歉!

vddsk6oq

vddsk6oq1#

你不必在背后使用邪恶的代码;- )您可以使用附加行为来完成此操作...

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>
mwg9r5ms

mwg9r5ms2#

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

ev7lccsx3#

由于Galasoft的MVVMLight现在已被弃用,我们可以使用CommunityToolkit.Mvvm包,并像这样使用它:

<DataGrid AutoGenerateColumns="True" 
          Name="DataGrid"
          ItemsSource="{Binding Items}">

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="AutoGeneratingColumn" SourceObject="{Binding ElementName=DataGrid}">
            <i:InvokeCommandAction Command="{Binding AutoGeneratingColumnCommand}" PassEventArgsToCommand="True"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</DataGrid>

注意,Items属性是一个简单的列表,它可以是一个ObservableCollection或任何东西。
获取激发事件的技巧是在加载窗口后加载数据,或者在加载后在Items属性上引发OnpropertyChanged。

<Window ...>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <i:InvokeCommandAction Command="{Binding LoadedCommand}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Window>

在视图模型中:

private RelayCommand<DataGridAutoGeneratingColumnEventArgs> myAutoGeneratingColumnCommand;
public RelayCommand<DataGridAutoGeneratingColumnEventArgs> AutoGeneratingColumnCommand
{
    get
    {
        if (myAutoGeneratingColumnCommand == null)
            myAutoGeneratingColumnCommand = new RelayCommand<DataGridAutoGeneratingColumnEventArgs>(AutoGeneratingColumnCommandAction);

        return myAutoGeneratingColumnCommand;
    }
}

private void AutoGeneratingColumnCommandAction(DataGridAutoGeneratingColumnEventArgs e)
{
    if (e.PropertyName == "Id")
    {
        e.Column.Width = 60;
    }
    else if (e.PropertyName == "Name")
    {
        e.Column.Header = "myName";
        e.Column.Width = new DataGridLength(1, DataGridLengthUnitType.Star);
    }
    else
        e.Cancel = true; // ignore all other properties and remove their column     
}

RelayCommand myLoadedCommand;
public RelayCommand LoadedCommand
{
    get
    {
        if (myLoadedCommand == null)
            myLoadedCommand = new RelayCommand(LoadedCommandAction);

        return myLoadedCommand;
    }
}

private void LoadedCommandAction()
{   
    Load(); // Populate the Items List
}
svmlkihl

svmlkihl4#

在使用MVVM开发项目的过程中,您会遇到必须在视图的代码隐藏中处理事件的情况,而EventToCommand只是简单地不起作用。您在Silverlight中尤其会发现这一点,但我从您的问题中假设您正在使用WPF。在视图的代码隐藏中进行一些事件处理是可以的。您甚至可以将该命令留在视图模型中,直接从事件处理程序中调用它。

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

相关问题