在编辑时修改 WPF DataGrid 中的用户控件

Posted

技术标签:

【中文标题】在编辑时修改 WPF DataGrid 中的用户控件【英文标题】:Modifying user control in WPF DataGrid on edit 【发布时间】:2014-05-15 22:26:38 【问题描述】:

我是 WPF 的新手,在尝试解决一个看似简单的问题时遇到了困难。

我需要设计一个数据表并允许用户对其进行编辑。当用户开始编辑单元格时,我需要在最右边的列 [OK] 和 [Cancel] 中显示一组按钮来接受或取消更改。当用户不编辑单元格时,应显示 [Delete] 按钮供用户删除行。

我编写了一个自定义控件,该控件将根据自定义 IsInEditMode 属性显示 [OK][Cancel] 或单个 [Delete] 按钮。

public partial class RowEditControl : UserControl

    public static DependencyProperty
            IsInEditModeProperty = DependencyProperty.Register( "IsInEditMode", 
                                                                    typeof(bool), 
                                                                    typeof(RowEditControl),
                                                                    new FrameworkPropertyMetadata(OnEditModeChanged));

    private static void OnEditModeChanged(DependencyObject aD, DependencyPropertyChangedEventArgs aE)
    
        //depending on the value show [Delete] or [Ok][Cancel] buttons
    

当用户开始编辑单元格时,我需要以某种方式设置 IsInEditMode。我一直在寻找整个 msdn 和这个论坛的示例/方法,但找不到任何东西。

我像这样以编程方式将自定义控件添加到最后一列:

        
        mwTagList.Columns[1].Width = new DataGridLength(1, DataGridLengthUnitType.Star);

        var fRowEditTemplate = new FrameworkElementFactory(typeof (RowEditControl));

        fRowEditTemplate.AddHandler(
                                   RowEditControl.DeleteClickedEvent,
                                   new RoutedEventHandler(OnDeleteRowBtn)
            );

        fRowEditTemplate.AddHandler(
                                 RowEditControl.OkClickedEvent,
                                 new RoutedEventHandler(OnRowEditOk));

        fRowEditTemplate.AddHandler(
                                 RowEditControl.CancelClickedEvent,
                                 new RoutedEventHandler(OnRowEditCancel));

        mwTagList.Columns.Add(
                              new DataGridTemplateColumn()
                              
                                  Header = "Delete Row",
                                  CellTemplate = new DataTemplate() VisualTree = fRowEditTemplate
                              
            );
    

非常感谢您提供的任何信息和提示!

【问题讨论】:

【参考方案1】:

我使用样式解决了这个问题:

<Style x:Key="MwControlCellStyle" TargetType="x:Type notesList:RowEditControl">
        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <!-- find DataGridRow parent object and trigger if it is in editing mode -->
                    <Condition Binding="Binding RelativeSource=RelativeSource FindAncestor, AncestorType=x:Type DataGridRow, Path=IsEditing" Value="True"></Condition>
                </MultiDataTrigger.Conditions>
                <Setter Property="IsInEditMode" Value="True"></Setter>
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>

【讨论】:

【参考方案2】:

DataGridRow 上有一个 IsEditing 依赖属性,因此您可以使用 XAML 和几个转换器来执行此操作。 XAML 的主要部分如下所示

<Window.Resources>
<viewModel:BooleanVisibleConverter x:Key="boolVisConv"/>
<viewModel:InverseBooleanVisibleConverter x:Key="invBoolVisConv"/>

<DataTemplate x:Key="DataGridButtonsTemplate">
    <StackPanel >
        <Button Content="Delete" Visibility ="Binding IsEditing, Mode=OneWay, Converter=StaticResource invBoolVisConv, RelativeSource=RelativeSource Mode=FindAncestor, AncestorType=DataGridRow"/>
        <Button Content="OK"  Visibility="Binding IsEditing, Mode=OneWay, Converter=StaticResource boolVisConv,RelativeSource=RelativeSource Mode=FindAncestor, AncestorType=DataGridRow"/>
        <Button Content="Cancel"  Visibility="Binding IsEditing, Mode=OneWay, Converter=StaticResource boolVisConv,RelativeSource=RelativeSource Mode=FindAncestor, AncestorType=DataGridRow"/>
    </StackPanel>
</DataTemplate>
</Window.Resources>

<DataGrid Grid.Row="1" ItemsSource="Binding MyData" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="Binding FirstField" Header="First Property"></DataGridTextColumn>
        <DataGridTextColumn Binding="Binding SecondField" Header="Second Property"></DataGridTextColumn>
        <DataGridTextColumn Binding="Binding ThirdField" Header="Third Property"></DataGridTextColumn>
        <DataGridTemplateColumn Header="Control" CellTemplate="StaticResource DataGridButtonsTemplate"></DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

这里有一个示例转换器,显然你需要其中两个,第二个将返回值反转

    [ValueConversion(typeof(bool), typeof(Visibility))]
public class BooleanVisibleConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    
        if (targetType != typeof(Visibility))
            throw new InvalidOperationException("The target must be a System.Windows.Visibility");

        return ((bool)value)? Visibility.Visible : Visibility.Collapsed;
    

    public object ConvertBack(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    
        throw new NotSupportedException();
    

您需要确定按下的是哪个按钮,因为每行都有一个。这里有一些关于如何做到这一点的想法

WPF DataGrid - Button in a column, getting the row from which it came on the Click event handler

【讨论】:

谢谢!我使用上述样式解决了这个问题,但这看起来也很酷。这也是如何使用转换器的一个很好的例子,我是 WPF 新手,从未使用过它们。

以上是关于在编辑时修改 WPF DataGrid 中的用户控件的主要内容,如果未能解决你的问题,请参考以下文章

WPF DataGrid 全行编辑

WPF DataGrid - 以编程方式将单元格设置为编辑模式

WPF Datagrid在鼠标双击时编辑单元格

wpf datagrid 输入编辑

WPF datagrid:禁用某些行中的编辑

无法编辑我的 DataGrid WPF Framework 4.5 的单元格