如何使WPF DataGridCell只读?
-
27-09-2019 - |
题
我明白你可以使整个数据网格或一整列readyonly(IsReadOnly =真)。然而,在细胞水平这个属性仅是准备好了。但我确实需要这种级别的粒度。有一个关于通过改变过去时的DataGrid是公共领域的源代码添加到IsReadOnly一排的博客,但现在我没有为DataGrid的源代码。有什么解决办法?
使细胞禁用(的IsEnabled =假)几乎符合我的需要。但问题是,你甚至不能单击禁用的单元格,选择行(我有充分的行选择模式)。
编辑:由于没有人回答了这个问题,所以我想这不是一个容易解决。这里是一个可能的解决方法:使细胞编辑。唯一的问题是,单击该单元格不选择行。我刚才注意到,当点击禁用电池时的DataGrid的MouseDown或MouseUp事件仍然被解雇。在此事件处理程序,如果我能计算出它点击该行,我可以以编程方式选择该行。然而,我无法弄清楚如何找到DataGrid.InputHitTest
基础行。可有人请给我一些提示?
解决方案
我遇到了同样的问题,该小区应该只读在某些行,但不是在其他人。这里是一个解决方法解决:
我们的想法是动态地切换两个模板之间的CellEditingTemplate
,一个是相同的所述一个在CellTemplate
,另一种是用于编辑。这使得编辑模式作用完全一样的非编辑细胞虽然它是处于编辑模式。
以下是这样做的,通知一些示例代码,这种方法需要DataGridTemplateColumn
:
首先,定义两个模板用于只读和编辑细胞:
<DataGrid>
<DataGrid.Resources>
<!-- the non-editing cell -->
<DataTemplate x:Key="ReadonlyCellTemplate">
<TextBlock Text="{Binding MyCellValue}" />
</DataTemplate>
<!-- the editing cell -->
<DataTemplate x:Key="EditableCellTemplate">
<TextBox Text="{Binding MyCellValue}" />
</DataTemplate>
</DataGrid.Resources>
</DataGrid>
然后定义与附加ContentPresenter
层和使用Trigger
数据模板来切换ContentTemplate
的ContentPresenter
,因此,上述两个模板可以动态由IsEditable
切换结合:
<DataGridTemplateColumn CellTemplate="{StaticResource ReadonlyCellTemplate}">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<!-- the additional layer of content presenter -->
<ContentPresenter x:Name="Presenter" Content="{Binding}" ContentTemplate="{StaticResource ReadonlyCellTemplate}" />
<DataTemplate.Triggers>
<!-- dynamically switch the content template by IsEditable binding -->
<DataTrigger Binding="{Binding IsEditable}" Value="True">
<Setter TargetName="Presenter" Property="ContentTemplate" Value="{StaticResource EditableCellTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
HTH
其他提示
使用IsTabStop =假和调焦=假最适合我很多搜索和实验后。
<DataGridTextColumn Header="My Column" Binding="{Binding Path=MyColumnValue}">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ReadOnly}" Value="True">
<Setter Property="IsTabStop" Value="False"></Setter>
<Setter Property="Focusable" Value="False"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
有是,你可能会认为你可以绑定到,结果就DataGridCell.IsReadOnly
属性
例如使用XAML这样的:
<!-- Won't work -->
<DataGrid Name="myDataGrid" ItemsSource="{Binding MyItems}">
<DataGrid.Resources>
<Style TargetType="DataGridCell">
<Setter Property="IsReadOnly" Value="{Binding MyIsReadOnly}" />
</Style>
</DataGrid.Resources>
<!-- Column definitions... -->
</DataGrid>
Unfortunantly这是行不通的,因为这个属性是不可写。结果 接下来,您可能会尝试拦截和停止鼠标事件,但是这不会阻止用户使用F2键进入编辑模式。
我sloved这个问题的方法是通过侦听在数据网格中PreviewExecutedEvent
然后有条件地标记它为已处理。结果,
例如。通过添加与此类似代码到我的窗口或用户控件的构造(或另一个更合适的地方):
myDataGrid.AddHandler(CommandManager.PreviewExecutedEvent,
(ExecutedRoutedEventHandler)((sender, args) =>
{
if (args.Command == DataGrid.BeginEditCommand)
{
DataGrid dataGrid = (DataGrid) sender;
DependencyObject focusScope = FocusManager.GetFocusScope(dataGrid);
FrameworkElement focusedElement = (FrameworkElement) FocusManager.GetFocusedElement(focusScope);
MyRowItemModel model = (MyRowItemModel) focusedElement.DataContext;
if (model.MyIsReadOnly)
{
args.Handled = true;
}
}
}));
通过这样做它像这样的细胞仍然可聚焦的和可选择的。结果 但是,用户将无法进入编辑模式,除非你的模型项允许它给定的行。结果 你会不会使用DataGridTemplateColumn遭受性能成本或复杂性。
我在我的申请通过在小区设置底层对象(例如复选框)解决了这个问题 - IsHitTestVisible = FALSE;可聚焦= FALSE;
var cb = this.dataGrid.Columns[1].GetCellContent(row) as CheckBox;
cb.IsHitTestVisible = false;
cb.Focusable = false;
“行” 是一个DataGridRow。 IsHitTestVisible =假,意味着你不能点击/选择/通过鼠标操纵底层的对象,但你仍然可以选择DataGridCell。调焦=假,意味着你不能选择/操作与键盘的基础对象。这给出了一个只读细胞的幻觉,但你仍然可以选择单元格,我敢肯定,如果DataGrid设立的的SelectionMode = FullRow 的,然后点击“只读”单元将选择整个行。
我的解决方案是使用结合有转换器的DataGridTemplateColumn。
<UserControl.Resources>
<c:isReadOnlyConverter x:Key="isRead"/>
</UserControl.Resources>
<DataGridTemplateColumn x:Name="exampleTemplate" Header="example:" Width="120" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="exampleCheckBox" VerticalAlignment="Center" IsEnabled="{Binding ElementName=exmpleTemplate, Path=IsReadOnly, Converter={StaticResource isRead}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
和所述转换器:
class isReadOnlyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
return !(bool)value;
}
catch (Exception)
{
return false;
}
}
根据@sohum评论,在这里你可以使用标记为答案响应的简化版本。
dataGrid.BeginningEdit += DataGrid_BeginningEdit;
(...)
private static void DataGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
{
//Actual content of the DataGridCell
FrameworkElement content = e.Column.GetCellContent(e.Row);
MyObject myObject = (MyObject)content.DataContext;
if (!myObject.CanEdit)
{
e.Cancel = true;
}
}
您可以在以后使用它作为附加属性的行为。
获取可选择的一种方式,只读文本细胞的DataGrid是使用模板和样式是这样的:
<DataGrid>
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Padding="0" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
<TextBox BorderThickness="0" MouseDoubleClick="DataGrid_TextBox_MouseDoubleClick" IsReadOnly="True" Padding="5" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.CellStyle>
和用于CS后端:
private void DataGrid_TextBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
(sender as TextBox).SelectAll();
}
这是一个有点晚了,但我一直在寻找到这个问题,以及这些解决方案的工作很好,但我需要的东西有点不同,我做了以下和它的工作原理完全一样,我想,什么问题是寻找。
我基本上我希望能够进入编辑模式用于小区和具有所有其他的模板和命令逻辑不能够编辑相同而细胞。
对于所有这样做的解决方案是将TextBox.IsReadOnly属性设置为true在DataGridCell风格与处理初始keydown事件
<Style TargetType="DataGridCell">
<Setter Property="TextBox.IsReadOnly" Value="True"/>
<EventSetter Event="PreviewKeyDown" Handler="cell_PreviewKeyDown"/>
</Style>
和后面将以下代码以停止初始修改
protected void cell_PreviewKeyDown(object sender, KeyEventArgs e)
{
DataGridCell cell = sender as DataGridCell;
if (cell.IsEditing == false &&
((Keyboard.Modifiers & ModifierKeys.Control) != ModifierKeys.Control)) //So that Ctrl+C keeps working
{
cell.IsEditing = true;
e.Handled = true;
}
}
希望这是有帮助的。
在我的情况下我用DataGridTextColumn。余设置ContentPresenter IsEnabled属性在样式如下,它工作正常 -
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}" >
<ContentPresenter IsEnabled="{Binding Path=IsEditable}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
<DataGridTextColumn Header="A"
Binding="{Binding Path=A}"/>
</DataGrid>
您可以用一个简单的数据模板做到这一点。
<DataGrid.Resources>
<DataTemplate x:Key="MyTemplate" DataType="MyRowDataType">
<TextBox Text="{Binding Value}" IsReadOnly="{Binding IsReadOnly}" />
</DataTemplate>
</DataGrid.Resources>
...
<DataGridTemplateColumn CellTemplate="{StaticResource MyTemplate}" />