如何根据某些条件阻止DataGridTemplateColumn进入编辑模式?

时间:2013-03-21 15:27:09

标签: c# wpf wpfdatagrid datagridtemplatecolumn editmode

我有一个可编辑的DataGridTemplateColumn。如果业务对象满足某些标准,我只希望用户能够编辑此列中单元格的内容。假设我的业务对象实现了INotifyPropertyChanged并具有三个属性: Name Department Sales 名称部门是字符串,而销售是双重的。

我希望用户只有在部门等于"零售"时才能编辑销售值。这是我可能用来执行此操作的数据网格:

<DataGrid ItemsSource="{Binding Path=MyTypeCollection}" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Path=Name, Mode=OneTime}" IsReadOnly="True" />
        <DataGridTextColumn Header="Department" Binding="{Binding Path=Department, Mode=OneTime}" IsReadOnly="True" />
        <DataGridTemplateColumn Header="Sales">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="{Binding Path=Sales, Mode=TwoWay}" Visibility="{Binding Path={StaticResource ResourceKey=IsRetail}}" />
                        <TextBlock Text="{Binding Path=Sales, Mode=OneWay}" Visibility="{Binding Path={StaticResource ResourceKey=IsNotRetail}}" />
                    </StackPanel>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBox Text="{Binding Path=Sales, Mode=TwoWay}" Visibility="{Binding Path={StaticResource ResourceKey=IsRetail}}" />
                        <TextBlock Text="{Binding Path=Sales, Mode=OneWay}" Visibility="{Binding Path={StaticResource ResourceKey=IsNotRetail}}" />
                    </StackPanel>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

我使用带有两个Text元素的堆栈面板。我在Text元素的Visibility中使用绑定来切换Text元素。如果我的行 Department 值不是&#34; Retail&#34;,我会在 Sales 列中显示一个TextBlock,无论该单元是否处于显示模式或编辑模式。

这对我来说似乎是一个笨拙的解决方案。有什么办法可以防止这些类型的细胞完全进入编辑模式吗?我只想在部门是&#34;零售&#34;的情况下允许编辑模式。这可能吗?

编辑:添加代码。

@Rachel。谢谢您的帮助。我想粘贴所有的datagrid XAML代码,以确保我的一切正确。

<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Path=Data}">

    <DataGrid.Resources>
        <DataTemplate x:Key="TextBoxTemplate">
            <TextBox Text="{Binding Path=Sales}" />
        </DataTemplate>
    </DataGrid.Resources>

    <DataGrid.Columns>
        <DataGridTextColumn Header="Department" Binding="{Binding Path=Department, Mode=OneTime}" />
        <DataGridTextColumn Header="Name" Binding="{Binding Path=Name, Mode=OneTime}" />

        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <ContentControl x:Name="salesControl">
                        <TextBlock Text="{Binding Sales}" />
                    </ContentControl>

                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding Department}" Value="Retail">
                            <Setter TargetName="salesControl" Property="ContentTemplate" Value="{StaticResource TextBoxTemplate}" />
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>

            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Sales}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

    </DataGrid.Columns>
</DataGrid>

我几乎得到了我想要的地方。当我点击Sales行中的Retail值时,会出现一个TextBox,但它没有值(请参阅here)。我不确定为什么它没有值,因为TextBoxTemplate中的TextBox指定了一个绑定。你知道为什么会这样吗?

编辑:我注意到此解决方案的另一个问题,我无法实际编辑“销售”列中的值。如果我尝试,该值将恢复为原始的预编辑值。

3 个答案:

答案 0 :(得分:3)

我会使用DataTrigger根据部门是否等于“零售”来切换TextBox.IsReadOnly等属性的值

<Style ...>
    <!-- Set Default -->
    <Setter Property="IsReadOnly" Value="True" />

    <Style.Triggers>
        <DataTrigger Binding="{Binding Department}" Value="Retail">
            <Setter Property="IsReadOnly" Value="False" />
        </DataTrigger>
    </Style.Triggers>
</Style>

如果您的DataGrid中不需要任何其他编辑,最简单的方法是在IsReadOnly="True"上设置DataGrid以完全禁用编辑,并在TextBox上设置此样式在DataGridTemplateColumn中。这将消除许多额外的XAML代码,如IsReadOnly="True"

<DataGrid ItemsSource="{Binding Path=MyTypeCollection}" 
          AutoGenerateColumns="False"
          IsReadOnly="True">

    <!-- This could also go in Window.Resources, UserControl.Resources, etc -->
    <DataGrid.Resources>
        <Style x:Key="SalesTextBoxStyle" TargetType="{x:Type TextBox}">
            <!-- Set Default -->
            <Setter Property="IsReadOnly" Value="True" />

            <Style.Triggers>
                <DataTrigger Binding="{Binding Department}" Value="Retail">
                    <Setter Property="IsReadOnly" Value="False" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.Resources>

    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
        <DataGridTextColumn Header="Department" Binding="{Binding Path=Department}" />
        <DataGridTemplateColumn Header="Sales">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBox Text="{Binding Path=Sales}" 
                             Style="{StaticResource SalesTextBoxStyle}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

如果您确实需要默认的DataGrid编辑功能,您仍然可以使用相同的功能,但在TextBox中只需要一个TextBlock / DataTemplate而不是StackPanel和多个对象。

如果您真的希望它在用户无法编辑时显示实际TextBlock而不是TextBox,您可以使用ContentControl并切换它具有ContentTemplate

DataTrigger媒体资源
<DataGrid.Resources>
    <DataTemplate x:Key="TextBoxTemplate">
        <TextBox Text="{Binding Path=.}" />
    </DataTemplate>
</DataGrid.Resources>

...

<DataGridTemplateColumn>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ContentControl x:Name="salesControl" Content="{Binding Sales}" />
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding Department}" Value="Retail">
                    <Setter TargetName="salesControl" 
                            Property="ContentTemplate" 
                            Value="{StaticResource TextBoxTemplate}" />
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

答案 1 :(得分:1)

您还可以订阅DataGrid的BeginningEdit事件,然后在代码隐藏中添加一个简单的检查。

在XAML中:

<DataGrid BeginningEdit="DataGrid_BeginningEdit" />

示例代码:

private void DataGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
{
    RowViewModel VM = (RowViewModel)((DataGrid)sender).SelectedItem;

    if (!VM.IsRetail) { e.Cancel = true; }
}

答案 2 :(得分:1)

我使用此代码完成了它。我不完全理解它,但它的工作原理我希望它能够工作。谢谢雷切尔!

<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Path=Data}">

    <DataGrid.Resources>
        <DataTemplate x:Key="TextBoxTemplate">
            <TextBox Text="{Binding Path=Text, StringFormat=c0}" />
        </DataTemplate>
    </DataGrid.Resources>

    <DataGrid.Columns>
        <DataGridTextColumn Header="Department" Binding="{Binding Path=Department, Mode=OneTime}" />
        <DataGridTextColumn Header="Name" Binding="{Binding Path=Name, Mode=OneTime}" />

        <DataGridTemplateColumn Header="Sales">
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <ContentControl x:Name="salesControl" DataContext="{Binding Path=.}">
                        <TextBlock Text="{Binding Path=Sales, Mode=TwoWay, StringFormat=c0}" />
                    </ContentControl>

                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding Department}" Value="Retail">
                            <Setter TargetName="salesControl" Property="ContentTemplate" Value="{StaticResource TextBoxTemplate}" />
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>

            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Sales, StringFormat=c0}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

    </DataGrid.Columns>
</DataGrid>