代码之家  ›  专栏  ›  技术社区  ›  joerage

带有一些只读行的wpf datagrid

  •  13
  • joerage  · 技术社区  · 15 年前

    我需要将一些wpf数据网格行显示为只读或不显示,这取决于绑定模型上的属性。

    怎么能做到?

    3 回复  |  直到 6 年前
        1
  •  21
  •   surfen    13 年前

    我也有同样的问题。 利用jsmith的答案和nigel spencer的博客中提供的信息,我提出了一个解决方案 不需要更改wpf datagrid源代码、子类化或将代码添加到视图的codebhind . 如您所见,我的解决方案对mvvm非常友好。

    它使用 Expression Blend Attached Behavior mechanism 因此,您需要安装Expression Blend SDK并添加对Microsoft.Expression.Interactions.dll的引用,但此行为很容易转换为 native attached behavior 如果你不喜欢的话。

    用途:

    <DataGrid 
        xmlns:Behaviors="clr-namespace:My.Common.Behaviors"
    ...
    >
        <i:Interaction.Behaviors>
             <Behaviors:DataGridRowReadOnlyBehavior/>
        </i:Interaction.Behaviors>
        <DataGrid.Resources>
            <Style TargetType="{x:Type DataGridRow}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsReadOnly}" Value="True"/>
                        <Setter Property="Behaviors:ReadOnlyService.IsReadOnly" Value="True"/>
                        <Setter Property="Foreground" Value="LightGray"/>
                        <Setter Property="ToolTipService.ShowOnDisabled" Value="True"/>
                        <Setter Property="ToolTip" Value="Disabled in ViewModel"/>
                    </DataTrigger>
    
                </Style.Triggers>
            </Style>
          </DataGrid.Resources>
    ...
    </DataGrid>
    

    只读服务.cs

    using System.Windows;
    
    namespace My.Common.Behaviors
    {
        internal class ReadOnlyService : DependencyObject
        {
            #region IsReadOnly
    
            /// <summary>
            /// IsReadOnly Attached Dependency Property
            /// </summary>
            private static readonly DependencyProperty BehaviorProperty =
                DependencyProperty.RegisterAttached("IsReadOnly", typeof(bool), typeof(ReadOnlyService),
                    new FrameworkPropertyMetadata(false));
    
            /// <summary>
            /// Gets the IsReadOnly property.
            /// </summary>
            public static bool GetIsReadOnly(DependencyObject d)
            {
                return (bool)d.GetValue(BehaviorProperty);
            }
    
            /// <summary>
            /// Sets the IsReadOnly property.
            /// </summary>
            public static void SetIsReadOnly(DependencyObject d, bool value)
            {
                d.SetValue(BehaviorProperty, value);
            }
    
            #endregion IsReadOnly
        }
    }
    

    datagridrowreadonlybehavior.cs

    using System;
    using System.Windows.Controls;
    using System.Windows.Interactivity;
    
    namespace My.Common.Behaviors
    {
        /// <summary>
        /// Custom behavior that allows for DataGrid Rows to be ReadOnly on per-row basis
        /// </summary>
        internal class DataGridRowReadOnlyBehavior : Behavior<DataGrid>
        {
            protected override void OnAttached()
            {
                base.OnAttached();
                if (this.AssociatedObject == null)
                    throw new InvalidOperationException("AssociatedObject must not be null");
    
                AssociatedObject.BeginningEdit += AssociatedObject_BeginningEdit;
            }
    
            private void AssociatedObject_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
            {
                var isReadOnlyRow = ReadOnlyService.GetIsReadOnly(e.Row);
                if (isReadOnlyRow)
                    e.Cancel = true;
            }
    
            protected override void OnDetaching()
            {
                AssociatedObject.BeginningEdit -= AssociatedObject_BeginningEdit;
            }
        }
    }
    
        2
  •  12
  •   Fittizio Casoncelli javajavajavajavajava    7 年前

    我找到了解决这个问题的几个简单方法。在我看来,最好的方法是连接到datagrid的beginningedit事件。这与Nigel Spencer在其文章中所做的类似,但您不必从DataGrid中重写它。这个解决方案很好,因为它不允许用户编辑该行中的任何单元格,但是它允许 允许他们选择行 .

    在代码隐藏中:

    private void MyList_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
    {
      if (((MyCustomObject)e.Row.Item).IsReadOnly)  //IsReadOnly is a property set in the MyCustomObject which is bound to each row
      {
        e.Cancel = true;
      }
    }
    

    在XAML中:

    <DataGrid ItemsSource="{Binding MyObservableCollection}"
              BeginningEdit="MyList_BeginningEdit">
      <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Name}"
                            Header="Name"/>
        <DataGridTextColumn Binding="{Binding Age}"
                            Header="Age"/>
      </DataGrid.Columns>
    </DataGrid>
    

    不同的解决方案 …这根本不允许用户选择行,但不需要代码隐藏中的其他代码。

    <DataGrid ItemsSource="{Binding MyObservableCollection}">
      <DataGrid.Resources>
        <Style TargetType="{x:Type DataGridRow}">
          <Style.Triggers>
            <DataTrigger Binding="{Binding IsReadOnly}"
                         Value="True" >
            <Setter Property="IsEnabled"
                    Value="False" />   <!-- You can also set "IsHitTestVisble" = False but please note that this won't prevent the user from changing the values using the keyboard arrows -->
            </DataTrigger>
    
          </Style.Triggers>
        </Style>
      </DataGrid.Resources>
    
      <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Name}"
                            Header="Name"/>
        <DataGridTextColumn Binding="{Binding Age}"
                            Header="Age"/>
      </DataGrid.Columns>
    </DataGrid>
    
        3
  •  3
  •   Ankush Madankar    6 年前

    我认为最简单的方法是向datagridrow类添加isreadonly属性。奈杰尔·斯宾塞写了一篇详细的文章 here .

    推荐文章