WPF DataGridCell読み取り専用にする方法?
-
27-09-2019 - |
質問
私は、あなたが全体のデータグリッドまたは列全体readyonly(IsReadOnlyの= true)を行うことができます理解しています。しかし、細胞レベルでこのプロパティは唯一の準備ができています。しかし、私は粒度のこのレベルが必要です。そこのDataGridはパブリックドメインだった昔のソースコードを変更することにより、行にIsReadOnlyの追加に関するブログですが、今私は、DataGridのソースコードを持っていません。回避策は何ですか?
は、セルに無効(でIsEnabled = false)を作ることはほとんど私の必要性を満たしています。しかし、問題は、あなたも(私は完全な行選択モードを持っている)の行を選択するために、無効セルをクリックすることができないということです。
編集:誰もがこの質問に答えていないので、私はそれが簡単に修正はないことを推測します。ここで可能な回避策は次のとおりです。セルが編集不可能にします。唯一の問題は、セルをクリックすると、行を選択していないということです。私はちょうど無効セルがクリックされたときに、データグリッドのMouseDownイベントまたはMouseUpイベントイベントはまだ解雇されていることに気づきました。私はそれがクリックされた行を見つけ出すことができれば、このイベントハンドラでは、私は、プログラムの行を選択することができます。しかし、私はDataGrid.InputHitTest
からの根本的な行を見つける方法を見つけ出すことができませんでした。誰かが私にいくつかのヒントを与えてくださいことはできますか?
解決
私は同じ問題に遭遇してきた、セルが読み取り専用にする必要がありますいくつかの行ではなく、他の人に。ここでは、回避策ソリューションは次のとおりです。
アイデアは動的2つのテンプレート間CellEditingTemplate
を切り替えることで、一方が他方を編集するためのものである、CellTemplate
におけるものと同じです。これは、編集モードであるが、編集モードが非編集セルとまったく同じ動作をすることができます。
以下は、このアプローチはDataGridTemplateColumn
が必要であることの通知、これを行うためのいくつかのサンプルコードです
まず、読み取り専用と編集の細胞のための2つのテンプレートを定義します:
<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>
上記2つのテンプレートが結合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 = FalseのとFocusableの= Falseの作品のベストを使用して多くの検索と実験後ます。
<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方法は、DataGrid上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 =偽の;フォーカス可能=偽;
var cb = this.dataGrid.Columns[1].GetCellContent(row) as CheckBox;
cb.IsHitTestVisible = false;
cb.Focusable = false;
"行" がDataGridRowあります。 IsHitTestVisible = falseを、あなたは/クリック選択/マウスで基礎となるオブジェクトを操作していますが、まだDataGridCellを選択することができます傾けることを意味します。フォーカス可能= falseを、あなたがキーボードで基礎となるオブジェクトを操作する/選択できないことを意味します。これは、読み取り専用セルの錯覚を与えるが、あなたはまだ、セルを選択することができますし、データグリッドは、「読み取り専用」のセルをクリックすると全体を選択しますし、のの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();
}
これは私もこのに探していた、少し遅れているものの、これらのソリューションはうまく動作しますが、私は少し違う何かを必要に応じて、私は次のようでしたし、私が望んでいたとの質問が探しているもののように、それは正確に動作します。
私は基本的に私は、セルの編集モードに入り、持ってできるようにしたかった他のすべてのテンプレートとコマンドロジックは同じながら、編集することができないことを、セルます。
は、すべてこのためのソリューションがDataGridCellスタイルでtrueにTextBox.IsReadOnlyプロパティを設定すると、初期の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}" />