我有一个可编辑的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指定了一个绑定。你知道为什么会这样吗?
编辑:我注意到此解决方案的另一个问题,我无法实际编辑“销售”列中的值。如果我尝试,该值将恢复为原始的预编辑值。
答案 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>