【问题标题】:WPF-MVVM: Handeling Event from within DataGrid StyleWPF-MVVM:从 DataGrid 样式中处理事件
【发布时间】:2013-04-18 13:52:27
【问题描述】:

我基于 WPF+MVVM 开发 Prism+MEF 应用程序,其中有许多 DataGrid,所以我构建了 DataGridStyle 以应用于所有模块中的所有 DataGrid。样式在列标题中添加过滤文本框,当文本框文本发生如下更改时,我使用 MVVM Light EventToCommand 触发 TextChanged 事件:(此代码存在于 DataGridStyle 资源字典中)

    <TextBox x:Name="filterTextBox" 
         HorizontalAlignment="Right" MinWidth="25" Height="Auto"
         OpacityMask="Black" Visibility="Collapsed" 
         Text=""
         TextWrapping="Wrap" Grid.Column="0" Grid.ColumnSpan="1">

            <i:Interaction.Triggers>
                <i:EventTrigger EventName="TextChanged">
                    <cmd:EventToCommand Command="{Binding DataContext.TextChangedCommand}"
                          PassEventArgsToCommand="True"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
   </TextBox>

然后我使用附加属性处理 ViewModel 中的 TextChangedCommand(与包含数据网格的视图有关):

#region TextChangedCommand----------------------------------------------------------------------------------------------

        static ICommand command; //1

        public static ICommand GetTextChangedCommand(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(TextChangedCommandProperty);
        }

        public static void SetTextChangedCommand(DependencyObject obj, ICommand value)
        {
            obj.SetValue(TextChangedCommandProperty, value);
        }

        // Using a DependencyProperty as the backing store for TextChangedCommand.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TextChangedCommandProperty =
            DependencyProperty.RegisterAttached("TextChangedCommand",
                                                 typeof(ICommand), 
                                                 typeof(SubsystemAllViewModel),
                                                 new UIPropertyMetadata(null, CommandChanged));


        static void CommandChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var fe = obj as FrameworkElement;
            command = e.NewValue as ICommand;
            fe.AddHandler(TextBox.TextChangedEvent, new TextChangedEventHandler(ExecuteCommand));
        }

        static void ExecuteCommand(object sender, TextChangedEventArgs e)
        {
            //Some  Code
        }


        #endregion

以及包含 Grid 的 View:

 <DataGrid  ItemsSource="{Binding Subsystems,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                   SelectedItem="{Binding Path=SelectedSubsystem, Mode=TwoWay}"                        
                   Name="SubsystemAllDataGrid"              
                   Style="{StaticResource DataGridStyle}"
                   Grid.Row="2">

            <DataGrid.Columns>
                <DataGridTextColumn Header="Serial" Binding="{Binding Path=Serial, Mode=TwoWay}"></DataGridTextColumn>
                <DataGridTextColumn Header="Type" Binding="{Binding Path=Type, Mode=TwoWay}"></DataGridTextColumn>
                <DataGridTextColumn Header="System" Binding="{Binding Path=System, Mode=TwoWay}"></DataGridTextColumn>
                <DataGridTextColumn Header="SubsystemNo"  Binding="{Binding Path=SubsystemNo, Mode=TwoWay}"></DataGridTextColumn>
                <DataGridTextColumn Header="Description" Binding="{Binding Path=Description, Mode=TwoWay}"></DataGridTextColumn>
                <DataGridTextColumn Header="Scope" Binding="{Binding Path=Scope, Mode=TwoWay}"></DataGridTextColumn>
                <DataGridTextColumn Header="Area" Binding="{Binding Path=Area, Mode=TwoWay}"></DataGridTextColumn>
                <DataGridTextColumn Header="Priority" Binding="{Binding Path=Priority, Mode=TwoWay}"></DataGridTextColumn>
                <DataGridTextColumn Header="DossierLocation" Binding="{Binding Path=DossierLocation, Mode=TwoWay}"></DataGridTextColumn>
                <DataGridTextColumn Header="Parts" Binding="{Binding Path=Parts, Mode=TwoWay}"></DataGridTextColumn>
                <DataGridTextColumn Header="Status" Binding="{Binding Path=Status, Mode=TwoWay}"></DataGridTextColumn>
                <DataGridTextColumn Header="StatusDate" Binding="{Binding Path=StatusDate, Mode=TwoWay}"></DataGridTextColumn>
                <DataGridTextColumn Header="MCDate" Binding="{Binding Path=MCDate, Mode=TwoWay}"></DataGridTextColumn>
                <DataGridTextColumn Header="PlnMCDate" Binding="{Binding Path=PlnMCDate, Mode=TwoWay}"></DataGridTextColumn>
                <DataGridTextColumn Header="Remark" Binding="{Binding Path=Remark, Mode=TwoWay}"></DataGridTextColumn>

            </DataGrid.Columns>

        </DataGrid>

问题是: 当我在数据网格的列标题之一的文本框中输入过滤器文本时,什么也没有发生,并且没有命中以下点的断点:

1-GetTextChangedCommand 和 SetTextChangedCommand

2-CommandChanged() 方法。

我是 wpf 的新手,所以我确定 WPF 或 C# 代码中存在错误......所以请帮助我修复这些错误。

注意:我不使用后面的代码。

提前致谢

【问题讨论】:

  • 这似乎是一个 MVVM-light 特定问题。

标签: wpf mvvm


【解决方案1】:

看起来您的命令绑定不起作用。请尝试以下操作:

Command="{Binding Path=TextChangedCommand}"

Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}} Path=DataContext.TextChangedCommand}"

【讨论】:

  • 我应用了这两个选项,但是当我在任何列标题的过滤器文本框中输入过滤器文本时仍然没有任何反应。
  • 为什么不将 TextBox 的 Text 属性绑定到 ViewModel 中的属性。所以你可以在这个属性的 setter 中调用 TextChangedCommand。
  • 我试过这样做,但我有两个问题,第一个问题:getter 被调用但 setter 从未调用我不知道为什么。第二个问题:我需要使用 EventToCommand 将事件参数传递给视图模型
【解决方案2】:

断点未命中使我遇到绑定问题。

您的命令的数据上下文需要设置为您的命令的定义位置。因此,如果您的命令是在视图模型中定义的,则需要使用以下内容,但将 ansestor 类型设置为绑定到您的视图模型的对象类型。这通常是您的视图,而不是数据网格:

 Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ViewType}} Path=DataContext.TextChangedCommand}"

因此,如果您的视图是窗口或用户控件,请将 ViewType 更改为相应的类型。

您还可以在运行应用时在输出窗口中查看是否为您的命令生成任何绑定错误。

编辑 1: 不要使用依赖属性,在视图模型中使用来自 MVVM-Light 的中继命令:

 this.YourRelayCommand = new RelayCommand( ExecuteYourCommand, CanYourCommandExecute);

  public RelayCommand YourRelayCommand{ get; private set; }

  public bool CanYourCommandExecute() {

    }

  public void ExecuteYourCommand() {
    //TODO: Do code here 
    }

【讨论】:

  • @J King:当我在过滤器文本框中输入文本时仍然没有任何反应。顺便说一句,我在 Attached 属性 RegisterAttached 语句中插入了一个断点,该语句在视图打开时被命中。
  • 您能否发布定义视图和数据网格的整个 xaml。您的输出窗口中是否出现任何绑定错误?
  • 另外,如果您使用的是 MVVM-Light,为什么不使用专为此目的设计的中继命令?
  • @J King :我的视图的整个 xaml 分为 3 部分,第一部分包含用于添加行、删除行等的按钮,第二部分用于我包含的网格我的问题,第三部分是页脚。
  • @J King:DataContext 是在视图后面的代码中设置的,因为我使用 MEF(Microsoft 可扩展性框架)并且在输出窗口中没有出现绑定错误。我必须使用 MVVM-Light 才能从 DataGrid 样式中触发事件,而无需使用后面的代码。
猜你喜欢
  • 2011-04-22
  • 2016-02-12
  • 1970-01-01
  • 2010-12-24
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
  • 1970-01-01
  • 2010-12-16
相关资源
最近更新 更多