WPF Datagrid包含一些只读行

joe*_*age 14 wpf datagrid readonly wpftoolkit

我需要将某些WPF Datagrid行显示为只读或不依赖于绑定模型上的属性.

如何才能做到这一点?

sur*_*fen 22

我有同样的问题.使用jsmith的答案和Nigel Spencer的博客中提供的信息,我提出了一个解决方案,它不需要更改WPF DataGrid源代码,子类化或添加代码来查看代码隐藏.如您所见,我的解决方案非常适合MVVM.

它使用Expression Blend Attached Behavior机制,因此您需要安装Expression Blend SDK并添加对Microsoft.Expression.Interactions.dll的引用,但如果您不喜欢这种行为,则可以轻松地将此行为转换为本机附加行为.

用法:

<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>
Run Code Online (Sandbox Code Playgroud)

ReadOnlyService.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
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您需要IsReadOnly属性才能使其工作,因此我添加了一个接口并将e.Row.Item转换为它,使得ReadOnlyService不必要,IMO.尽管如此,大+1.干杯 (2认同)

jav*_*ava 14

我找到了几个解决这个问题的简单方法.我认为最好的是连接到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;
  }
}
Run Code Online (Sandbox Code Playgroud)

在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>
Run Code Online (Sandbox Code Playgroud)

不同的解决方案 ......这不允许用户选择行,但不需要后面的代码中的其他代码.

<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>
Run Code Online (Sandbox Code Playgroud)

  • 仅 XAML 方法更好、更干净:) (2认同)