Saya ingin pengguna dapat memasukkan sel ke dalam mode pengeditan dan menyorot baris yang berisi sel dengan satu klik. Secara default, ini adalah klik dua kali.
Bagaimana cara mengganti atau menerapkan ini?
Saya ingin pengguna dapat memasukkan sel ke dalam mode pengeditan dan menyorot baris yang berisi sel dengan satu klik. Secara default, ini adalah klik dua kali.
Bagaimana cara mengganti atau menerapkan ini?
Jawaban:
Berikut adalah cara saya menyelesaikan masalah ini:
<DataGrid DataGridCell.Selected="DataGridCell_Selected"
ItemsSource="{Binding Source={StaticResource itemView}}">
<DataGrid.Columns>
<DataGridTextColumn Header="Nom" Binding="{Binding Path=Name}"/>
<DataGridTextColumn Header="Age" Binding="{Binding Path=Age}"/>
</DataGrid.Columns>
</DataGrid>
DataGrid ini terikat ke CollectionViewSource (Berisi objek dummy Person ).
Keajaiban terjadi di sana: DataGridCell.Selected = "DataGridCell_Selected" .
Saya cukup mengaitkan Acara yang Dipilih dari sel DataGrid, dan memanggil BeginEdit () di Datagrid.
Berikut adalah kode di belakang untuk event handler:
private void DataGridCell_Selected(object sender, RoutedEventArgs e)
{
// Lookup for the source to be DataGridCell
if (e.OriginalSource.GetType() == typeof(DataGridCell))
{
// Starts the Edit on the row;
DataGrid grd = (DataGrid)sender;
grd.BeginEdit(e);
}
}
SelectionUnit
properti pada datagrid ke Cell
.
grd.BeginEdit(e)
, saya ingin TextBox di sel itu memiliki fokus. Bagaimana saya bisa melakukan itu? Saya mencoba memanggil FindName("txtBox")
DataGridCell dan DataGrid, tetapi mengembalikan null untuk saya.
Jawaban dari Micael Bergeron adalah awal yang baik bagi saya untuk menemukan solusi yang berhasil untuk saya. Untuk memungkinkan pengeditan satu klik juga untuk Sel di baris yang sama yang sudah dalam mode edit saya harus menyesuaikannya sedikit. Menggunakan Sel SelectionUnit bukanlah pilihan bagi saya.
Alih-alih menggunakan DataGridCell.Selected Event yang hanya diaktifkan untuk pertama kalinya sel baris diklik, saya menggunakan Event DataGridCell.GotFocus.
<DataGrid DataGridCell.GotFocus="DataGrid_CellGotFocus" />
Jika Anda melakukannya, Anda akan selalu fokus pada sel yang benar dan dalam mode edit, tetapi tidak ada kontrol di sel yang akan difokuskan, ini saya selesaikan seperti ini
private void DataGrid_CellGotFocus(object sender, RoutedEventArgs e)
{
// Lookup for the source to be DataGridCell
if (e.OriginalSource.GetType() == typeof(DataGridCell))
{
// Starts the Edit on the row;
DataGrid grd = (DataGrid)sender;
grd.BeginEdit(e);
Control control = GetFirstChildByType<Control>(e.OriginalSource as DataGridCell);
if (control != null)
{
control.Focus();
}
}
}
private T GetFirstChildByType<T>(DependencyObject prop) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(prop); i++)
{
DependencyObject child = VisualTreeHelper.GetChild((prop), i) as DependencyObject;
if (child == null)
continue;
T castedProp = child as T;
if (castedProp != null)
return castedProp;
castedProp = GetFirstChildByType<T>(child);
if (castedProp != null)
return castedProp;
}
return null;
}
Dari: http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing
XAML:
<!-- SINGLE CLICK EDITING -->
<Style TargetType="{x:Type dg:DataGridCell}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown"></EventSetter>
</Style>
KODE DI BELAKANG:
//
// SINGLE CLICK EDITING
//
private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DataGridCell cell = sender as DataGridCell;
if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
{
if (!cell.IsFocused)
{
cell.Focus();
}
DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
if (dataGrid != null)
{
if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
{
if (!cell.IsSelected)
cell.IsSelected = true;
}
else
{
DataGridRow row = FindVisualParent<DataGridRow>(cell);
if (row != null && !row.IsSelected)
{
row.IsSelected = true;
}
}
}
}
}
static T FindVisualParent<T>(UIElement element) where T : UIElement
{
UIElement parent = element;
while (parent != null)
{
T correctlyTyped = parent as T;
if (correctlyTyped != null)
{
return correctlyTyped;
}
parent = VisualTreeHelper.GetParent(parent) as UIElement;
}
return null;
}
Solusi dari http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing bekerja sangat baik untuk saya, tetapi saya mengaktifkannya untuk setiap DataGrid menggunakan Gaya yang ditentukan dalam ResourceDictionary. Untuk menggunakan penangan dalam kamus sumber daya, Anda perlu menambahkan file di belakang kode ke dalamnya. Inilah cara Anda melakukannya:
Ini adalah Kamus Sumber Daya DataGridStyles.xaml :
<ResourceDictionary x:Class="YourNamespace.DataGridStyles"
x:ClassModifier="public"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="DataGrid">
<!-- Your DataGrid style definition goes here -->
<!-- Cell style -->
<Setter Property="CellStyle">
<Setter.Value>
<Style TargetType="DataGridCell">
<!-- Your DataGrid Cell style definition goes here -->
<!-- Single Click Editing -->
<EventSetter Event="PreviewMouseLeftButtonDown"
Handler="DataGridCell_PreviewMouseLeftButtonDown" />
</Style>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Perhatikan atribut x: Class di elemen root. Buat file kelas. Dalam contoh ini akan menjadi DataGridStyles.xaml.cs . Letakkan kode ini di dalam:
using System.Windows.Controls;
using System.Windows;
using System.Windows.Input;
namespace YourNamespace
{
partial class DataGridStyles : ResourceDictionary
{
public DataGridStyles()
{
InitializeComponent();
}
// The code from the myermian's answer goes here.
}
Saya lebih suka cara ini berdasarkan saran Dušan Knežević. Anda mengklik itu saja))
<DataGrid.Resources>
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver"
Value="True" />
<Condition Property="IsReadOnly"
Value="False" />
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="IsEditing"
Value="True" />
</MultiTrigger.Setters>
</MultiTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
Saya menyelesaikannya dengan menambahkan pemicu yang menetapkan properti IsEditing dari DataGridCell ke True saat mouse di atasnya. Itu memecahkan sebagian besar masalah saya. Ia bekerja dengan combobox juga.
<Style TargetType="DataGridCell">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsEditing" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
Saya mencari sel pengeditan dengan sekali klik di MVVM dan ini adalah cara lain untuk melakukannya.
Menambahkan perilaku di xaml
<UserControl xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:myBehavior="clr-namespace:My.Namespace.To.Behavior">
<DataGrid>
<i:Interaction.Behaviors>
<myBehavior:EditCellOnSingleClickBehavior/>
</i:Interaction.Behaviors>
</DataGrid>
</UserControl>
Kelas EditCellOnSingleClickBehavior memperluas System.Windows.Interactivity.Behavior;
public class EditCellOnSingleClick : Behavior<DataGrid>
{
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.LoadingRow += this.OnLoadingRow;
this.AssociatedObject.UnloadingRow += this.OnUnloading;
}
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.LoadingRow -= this.OnLoadingRow;
this.AssociatedObject.UnloadingRow -= this.OnUnloading;
}
private void OnLoadingRow(object sender, DataGridRowEventArgs e)
{
e.Row.GotFocus += this.OnGotFocus;
}
private void OnUnloading(object sender, DataGridRowEventArgs e)
{
e.Row.GotFocus -= this.OnGotFocus;
}
private void OnGotFocus(object sender, RoutedEventArgs e)
{
this.AssociatedObject.BeginEdit(e);
}
}
Voila!
Ada dua masalah dengan jawaban pengguna2134678. Yang satu sangat kecil dan tidak memiliki efek fungsional. Yang lainnya cukup signifikan.
Masalah pertama adalah bahwa GotFocus sebenarnya dipanggil terhadap DataGrid, bukan DataGridCell dalam praktiknya. Qualifier DataGridCell di XAML berlebihan.
Masalah utama yang saya temukan dengan jawabannya adalah bahwa perilaku tombol Enter rusak. Enter akan memindahkan Anda ke sel berikutnya di bawah sel saat ini dalam perilaku DataGrid normal. Namun yang sebenarnya terjadi di balik layar adalah event GotFocus akan dipanggil dua kali. Setelah sel saat ini kehilangan fokus, dan setelah sel baru mendapatkan fokus. Tapi selama BeginEdit dipanggil di sel pertama itu, sel berikutnya tidak akan pernah diaktifkan. Hasilnya adalah Anda memiliki pengeditan sekali klik, tetapi siapa pun yang tidak benar-benar mengklik kisi akan merasa tidak nyaman, dan perancang antarmuka pengguna tidak boleh berasumsi bahwa semua pengguna menggunakan mouse. (Pengguna keyboard dapat menyiasatinya dengan menggunakan Tab, tetapi itu tetap berarti mereka melompati rintangan yang seharusnya tidak perlu.)
Jadi solusi untuk masalah ini? Tangani peristiwa KeyDown untuk sel dan jika Kuncinya adalah tombol Enter, setel bendera yang menghentikan pengaktifan BeginEdit pada sel pertama. Sekarang tombol Enter berfungsi sebagaimana mestinya.
Untuk memulai, tambahkan Style berikut ke DataGrid Anda:
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}" x:Key="SingleClickEditingCellStyle">
<EventSetter Event="KeyDown" Handler="DataGridCell_KeyDown" />
</Style>
</DataGrid.Resources>
Terapkan gaya itu ke properti "CellStyle", kolom yang ingin Anda aktifkan sekali klik.
Kemudian dalam kode di belakang Anda memiliki yang berikut ini di penangan GotFocus Anda (perhatikan bahwa saya menggunakan VB di sini karena itulah yang diinginkan klien "permintaan kisi data satu klik" sebagai bahasa pengembangan):
Private _endEditing As Boolean = False
Private Sub DataGrid_GotFocus(ByVal sender As Object, ByVal e As RoutedEventArgs)
If Me._endEditing Then
Me._endEditing = False
Return
End If
Dim cell = TryCast(e.OriginalSource, DataGridCell)
If cell Is Nothing Then
Return
End If
If cell.IsReadOnly Then
Return
End If
DirectCast(sender, DataGrid).BeginEdit(e)
.
.
.
Kemudian Anda menambahkan handler Anda untuk acara KeyDown:
Private Sub DataGridCell_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
If e.Key = Key.Enter Then
Me._endEditing = True
End If
End Sub
Sekarang Anda memiliki DataGrid yang tidak mengubah perilaku dasar apa pun dari implementasi out-of-the-box namun mendukung pengeditan sekali klik.
Saya tahu bahwa saya agak terlambat ke pesta tetapi saya memiliki masalah yang sama dan menemukan solusi yang berbeda:
public class DataGridTextBoxColumn : DataGridBoundColumn
{
public DataGridTextBoxColumn():base()
{
}
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
throw new NotImplementedException("Should not be used.");
}
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
var control = new TextBox();
control.Style = (Style)Application.Current.TryFindResource("textBoxStyle");
control.FontSize = 14;
control.VerticalContentAlignment = VerticalAlignment.Center;
BindingOperations.SetBinding(control, TextBox.TextProperty, Binding);
control.IsReadOnly = IsReadOnly;
return control;
}
}
<DataGrid Grid.Row="1" x:Name="exportData" Margin="15" VerticalAlignment="Stretch" ItemsSource="{Binding CSVExportData}" Style="{StaticResource dataGridStyle}">
<DataGrid.Columns >
<local:DataGridTextBoxColumn Header="Sample ID" Binding="{Binding SampleID}" IsReadOnly="True"></local:DataGridTextBoxColumn>
<local:DataGridTextBoxColumn Header="Analysis Date" Binding="{Binding Date}" IsReadOnly="True"></local:DataGridTextBoxColumn>
<local:DataGridTextBoxColumn Header="Test" Binding="{Binding Test}" IsReadOnly="True"></local:DataGridTextBoxColumn>
<local:DataGridTextBoxColumn Header="Comment" Binding="{Binding Comment}"></local:DataGridTextBoxColumn>
</DataGrid.Columns>
</DataGrid>
Seperti yang Anda lihat, saya menulis DataGridTextColumn saya sendiri yang mewarisi semuanya dari DataGridBoundColumn. Dengan menimpa Metode GenerateElement dan mengembalikan kontrol Textbox tepat di sana, Metode untuk menghasilkan Elemen Pengeditan tidak pernah dipanggil. Dalam proyek yang berbeda saya menggunakan ini untuk mengimplementasikan kolom Datepicker, jadi ini harus berfungsi untuk kotak centang dan kotak kombo juga.
Ini tampaknya tidak mempengaruhi sisa perilaku datagrids .. Setidaknya saya belum melihat adanya efek samping dan saya tidak mendapat umpan balik negatif sejauh ini.
Solusi sederhana jika Anda setuju dengan itu sel Anda tetap menjadi kotak teks (tidak ada perbedaan antara mode edit dan non-edit). Dengan cara ini pengeditan sekali klik bekerja di luar kotak. Ini berfungsi dengan elemen lain seperti kotak kombo dan tombol juga. Jika tidak, gunakan solusi di bawah pembaruan.
<DataGridTemplateColumn Header="My Column header">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding MyProperty } />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Saya mencoba semua yang saya temukan di sini dan di google dan bahkan mencoba membuat versi saya sendiri. Tetapi setiap jawaban / solusi bekerja terutama untuk kolom kotak teks tetapi tidak bekerja dengan semua elemen lainnya (kotak centang, kotak kombo, kolom tombol), atau bahkan merusak kolom elemen lainnya atau memiliki beberapa efek samping lainnya. Terima kasih Microsoft untuk membuat datagrid berperilaku buruk dan memaksa kami untuk membuat peretasan tersebut. Karena itu saya memutuskan untuk membuat versi yang dapat diterapkan dengan gaya ke kolom textbox secara langsung tanpa mempengaruhi kolom lain.
Saya menggunakan solusi ini dan jawaban @ my dan memodifikasinya menjadi perilaku terlampir. http://wpf-tutorial-net.blogspot.com/2016/05/wpf-datagrid-edit-cell-on-single-click.html
Tambahkan Gaya ini. Ini BasedOn
penting ketika Anda menggunakan beberapa gaya mewah untuk datagrid Anda dan Anda tidak ingin kehilangannya.
<Window.Resources>
<Style x:Key="SingleClickEditStyle" TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Setter Property="local:DataGridTextBoxSingleClickEditBehavior.Enable" Value="True" />
</Style>
</Window.Resources>
Terapkan gaya dengan CellStyle
ke setiap Anda DataGridTextColumns
seperti ini:
<DataGrid ItemsSource="{Binding MyData}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="My Header" Binding="{Binding Comment}" CellStyle="{StaticResource SingleClickEditStyle}" />
</DataGrid.Columns>
</DataGrid>
Dan sekarang tambahkan kelas ini ke namespace yang sama dengan MainViewModel Anda (atau Namespace yang berbeda. Tapi kemudian Anda perlu menggunakan awalan namespace selain local
). Selamat datang di dunia kode boilerplate jelek dari perilaku terlampir.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace YourMainViewModelNameSpace
{
public static class DataGridTextBoxSingleClickEditBehavior
{
public static readonly DependencyProperty EnableProperty = DependencyProperty.RegisterAttached(
"Enable",
typeof(bool),
typeof(DataGridTextBoxSingleClickEditBehavior),
new FrameworkPropertyMetadata(false, OnEnableChanged));
public static bool GetEnable(FrameworkElement frameworkElement)
{
return (bool) frameworkElement.GetValue(EnableProperty);
}
public static void SetEnable(FrameworkElement frameworkElement, bool value)
{
frameworkElement.SetValue(EnableProperty, value);
}
private static void OnEnableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is DataGridCell dataGridCell)
dataGridCell.PreviewMouseLeftButtonDown += DataGridCell_PreviewMouseLeftButtonDown;
}
private static void DataGridCell_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
EditCell(sender as DataGridCell, e);
}
private static void EditCell(DataGridCell dataGridCell, RoutedEventArgs e)
{
if (dataGridCell == null || dataGridCell.IsEditing || dataGridCell.IsReadOnly)
return;
if (dataGridCell.IsFocused == false)
dataGridCell.Focus();
var dataGrid = FindVisualParent<DataGrid>(dataGridCell);
dataGrid?.BeginEdit(e);
}
private static T FindVisualParent<T>(UIElement element) where T : UIElement
{
var parent = VisualTreeHelper.GetParent(element) as UIElement;
while (parent != null)
{
if (parent is T parentWithCorrectType)
return parentWithCorrectType;
parent = VisualTreeHelper.GetParent(parent) as UIElement;
}
return null;
}
}
}
<DataGridComboBoxColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="cal:Message.Attach"
Value="[Event MouseLeftButtonUp] = [Action ReachThisMethod($source)]"/>
</Style>
</DataGridComboBoxColumn.CellStyle>
public void ReachThisMethod(object sender)
{
((System.Windows.Controls.DataGridCell)(sender)).IsEditing = true;
}