Quero que o usuário seja capaz de colocar a célula no modo de edição e destacar a linha na qual a célula está contida com um único clique. Por padrão, é um clique duplo.
Este DataGrid está vinculado a um CollectionViewSource (contendo objetos Person fictícios ).
A mágica acontece lá: DataGridCell.Selected = "DataGridCell_Selected" .
Simplesmente conecto o Evento Selecionado da célula DataGrid e chamo BeginEdit () no DataGrid.
Aqui está o código por trás do manipulador de eventos:
privatevoidDataGridCell_Selected(object sender,RoutedEventArgs e){// Lookup for the source to be DataGridCellif(e.OriginalSource.GetType()==typeof(DataGridCell)){// Starts the Edit on the row;DataGrid grd =(DataGrid)sender;
grd.BeginEdit(e);}}
Você pode contornar o problema de linha já selecionada definindo a SelectionUnitpropriedade no DataGrid como Cell.
Matt Winckler
Suponha que eu tenha um TextBox em meu DataGridCell. Depois que eu ligar grd.BeginEdit(e), quero que o TextBox dessa célula tenha o foco. Como eu posso fazer isso? Eu tentei chamar FindName("txtBox")o DataGridCell e o DataGrid, mas ele retornou null para mim.
user1214135
GotFocus = "DataGrid_GotFocus" parece estar faltando?
sinérgico de
4
Isso funciona bem, mas eu não recomendaria fazer isso. Usei isso em meu projeto e decidi voltar ao comportamento padrão de GD. No futuro, quando seu DG crescer e se tornar complexo, você terá problemas com validação, adicionando novas linhas e outros comportamentos estranhos.
white.zaz
1
@ white.zaz ficou satisfeito com o cliente depois que você reverteu o comportamento padrão do DG? Porque o principal motivo para fazer essa pergunta foi que a edição em recursos padrão do DG não é amigável, pois precisa ser clicada muitas vezes antes que o DG chegue ao modo Editar.
AEMLoviji
42
A resposta de Micael Bergeron foi um bom começo para eu encontrar uma solução que está funcionando para mim. Para permitir a edição com um único clique também para células na mesma linha que já estão no modo de edição, tive que ajustar um pouco. Usar o SelectionUnit Cell não era uma opção para mim.
Em vez de usar o evento DataGridCell.Selected, que só é disparado pela primeira vez em que uma célula da linha é clicada, usei o evento DataGridCell.GotFocus.
Se você fizer isso, você terá sempre a célula correta focada e no modo de edição, mas nenhum controle na célula estará focado, isso eu resolvi assim
privatevoidDataGrid_CellGotFocus(object sender,RoutedEventArgs e){// Lookup for the source to be DataGridCellif(e.OriginalSource.GetType()==typeof(DataGridCell)){// Starts the Edit on the row;DataGrid grd =(DataGrid)sender;
grd.BeginEdit(e);Control control =GetFirstChildByType<Control>(e.OriginalSourceasDataGridCell);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)asDependencyObject;if(child ==null)continue;
T castedProp = child as T;if(castedProp !=null)return castedProp;
castedProp =GetFirstChildByType<T>(child);if(castedProp !=null)return castedProp;}returnnull;}
isso não funciona em certos casos, e é mais complicado do que a solução de Micael Bergerons.
SwissCoder
Para mim, essa quase foi a solução. Eu precisava adicionar um manipulador de eventos "PreviewMouseLeftButtonUp" e colocar exatamente o mesmo código.
Néstor Sánchez A.
isso também não funciona quando você tem uma caixa de combinação. o clique de visualização vê cliques no pop-up da caixa de combinação, então a chamada de cell.focus estraga tudo. A correção mais fácil é adicionar uma seção que examina a fonte original dos eventos do mouse, usando FindVisualParent para ver se está dentro do datagrid. se não, não faça nenhum dos outros trabalhos.
John Gardner
7
A solução de http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing funcionou muito bem para mim, mas eu a habilitei para cada DataGrid usando um estilo definido em um ResourceDictionary. Para usar manipuladores em dicionários de recursos, você precisa adicionar um arquivo code-behind a ele. Veja como você faz:
Este é um Dicionário de recursos DataGridStyles.xaml :
<ResourceDictionaryx:Class="YourNamespace.DataGridStyles"x:ClassModifier="public"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><StyleTargetType="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>
Observe o atributo x: Class no elemento raiz. Crie um arquivo de classe. Neste exemplo, seria DataGridStyles.xaml.cs . Coloque este código dentro de:
usingSystem.Windows.Controls;usingSystem.Windows;usingSystem.Windows.Input;namespaceYourNamespace{partialclassDataGridStyles:ResourceDictionary{publicDataGridStyles(){InitializeComponent();}// The code from the myermian's answer goes here.}
Isso não funciona se uma caixa de combinação for usada como um modelo de edição, eu presumiria que outras opções, como a caixa de seleção de que os eventos de captura do mouse também quebrariam
Steve
Para mim, isso funciona com colunas combobox, mas a caixa de texto da "nova linha de item" (última linha) tem um comportamento estranho: no primeiro clique, obtenho o foco de entrada e posso digitar coisas. Quando movo o mouse para fora da célula , o valor da caixa de texto desaparece. Ao digitar mais, o Texto recém-inserido é salvo corretamente (ele cria uma nova entrada conforme desejado). Isso também ocorre mesmo com um ComboboxColumn.
FrankM
Inicialmente parecia estar funcionando bem, mas baguncei totalmente o meu DataGrid, quando tento ordenar, todos esses valores sumiram, sem esse código tudo funciona bem com ordenação.
Chandraprakash
3
Resolvi isso adicionando um gatilho que define a propriedade IsEditing de DataGridCell como True quando o mouse está sobre ele. Isso resolveu a maioria dos meus problemas. Também funciona com caixas de combinação.
Não funciona ... ele perde a edição assim que o mouse sai da célula. Então você 1) clique com o botão esquerdo na célula que deseja editar. 2) mova o mouse para fora do caminho 3) Comece a digitar. Sua digitação não funciona porque a célula não está mais no modo de edição.
Skarsnik
1
não funciona para mim também. impede a edição da caixa de texto para mim
Blechdose
Mas tem um problema com essa abordagem, eu havia travado a 1ª coluna para edição, com essa abordagem, isso está tornando a 1ª coluna também editável!
Chandraprakash
3
Procuro editar célula em um único clique no MVVM e esta é uma outra maneira de fazer isso.
Existem dois problemas com a resposta do usuário2134678. Um é muito pequeno e não tem efeito funcional. O outro é bastante significativo.
O primeiro problema é que o GotFocus está realmente sendo chamado contra o DataGrid, não o DataGridCell na prática. O qualificador DataGridCell no XAML é redundante.
O principal problema que encontrei com a resposta é que o comportamento da tecla Enter está quebrado. Enter deve mover você para a próxima célula abaixo da célula atual no comportamento normal do DataGrid. No entanto, o que realmente acontece nos bastidores é que o evento GotFocus será chamado duas vezes. Uma vez a célula atual perdendo o foco e outra vez a nova célula ganhando foco. Mas, enquanto BeginEdit for chamado na primeira célula, a próxima célula nunca será ativada. O resultado é que você tem edição com um clique, mas qualquer um que não esteja literalmente clicando na grade ficará incomodado, e um designer de interface de usuário não deve presumir que todos os usuários estão usando mouses. (Os usuários de teclado podem contornar isso usando Tab, mas isso ainda significa que eles estão se esforçando para não precisar fazer isso.)
Então, a solução para esse problema? Manipule o evento KeyDown para a célula e se a tecla for a tecla Enter, defina um sinalizador que impeça o BeginEdit de disparar na primeira célula. Agora a tecla Enter se comporta como deveria.
Para começar, adicione o seguinte estilo ao seu DataGrid:
Aplique esse estilo à propriedade "CellStyle" nas colunas para as quais deseja habilitar um clique.
Então, no código atrás, você tem o seguinte em seu manipulador GotFocus (observe que estou usando VB aqui porque é isso que nosso cliente de "solicitação de grade de dados com um clique" queria como linguagem de desenvolvimento):
Em seguida, você adiciona seu manipulador para o evento KeyDown:
PrivateSubDataGridCell_KeyDown(ByVal sender AsObject,ByVal e AsKeyEventArgs)If e.Key=Key.EnterThenMe._endEditing =TrueEndIfEndSub
Agora você tem um DataGrid que não mudou nenhum comportamento fundamental da implementação pronta para uso e ainda oferece suporte à edição com um único clique.
Sei que estou um pouco atrasado para a festa, mas tive o mesmo problema e encontrei uma solução diferente:
publicclassDataGridTextBoxColumn:DataGridBoundColumn{publicDataGridTextBoxColumn():base(){}protectedoverrideFrameworkElementGenerateEditingElement(DataGridCell cell,object dataItem){thrownewNotImplementedException("Should not be used.");}protectedoverrideFrameworkElementGenerateElement(DataGridCell cell,object dataItem){var control =newTextBox();
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;}}<DataGridGrid.Row="1" x:Name="exportData"Margin="15"VerticalAlignment="Stretch"ItemsSource="{Binding CSVExportData}"Style="{StaticResource dataGridStyle}"><DataGrid.Columns><local:DataGridTextBoxColumnHeader="Sample ID"Binding="{Binding SampleID}"IsReadOnly="True"></local:DataGridTextBoxColumn><local:DataGridTextBoxColumnHeader="Analysis Date"Binding="{Binding Date}"IsReadOnly="True"></local:DataGridTextBoxColumn><local:DataGridTextBoxColumnHeader="Test"Binding="{Binding Test}"IsReadOnly="True"></local:DataGridTextBoxColumn><local:DataGridTextBoxColumnHeader="Comment"Binding="{Binding Comment}"></local:DataGridTextBoxColumn></DataGrid.Columns></DataGrid>
Como você pode ver, escrevi meu próprio DataGridTextColumn herdando tudo do DataGridBoundColumn. Substituindo o Método GenerateElement e retornando um controle Textbox ali mesmo, o Método para gerar o Elemento de Edição nunca é chamado. Em um projeto diferente, usei isso para implementar uma coluna Datepicker, então isso deve funcionar para caixas de seleção e comboboxes também.
Isso não parece afetar o comportamento do restante dos datagrids ... Pelo menos, não notei nenhum efeito colateral nem recebi feedback negativo até agora.
Uma solução simples se você concordar que sua célula permaneça uma caixa de texto (sem distinção entre o modo de edição e não edição). Desta forma, a edição com um único clique funciona imediatamente. Isso funciona com outros elementos como combobox e botões também. Caso contrário, use a solução abaixo da atualização.
Tentei tudo o que encontrei aqui e no google e até tentei criar minhas próprias versões. Mas cada resposta / solução funcionou principalmente para colunas de caixa de texto, mas não funcionou com todos os outros elementos (caixas de seleção, caixas de combinação, colunas de botões), ou mesmo quebrou essas outras colunas de elemento ou teve alguns outros efeitos colaterais. Obrigado microsoft por fazer o datagrid se comportar daquela maneira feia e nos forçar a criar esses hacks. Por isso decidi fazer uma versão que pode ser aplicada com um estilo a uma coluna de caixa de texto diretamente sem afetar as outras colunas.
Recursos
Nenhum código por trás. MVVM amigável.
Funciona ao clicar em diferentes células da caixa de texto na mesma linha ou em linhas diferentes.
E agora adicione esta classe ao mesmo namespace que seu MainViewModel (ou um namespace diferente. Mas então você precisará usar um outro prefixo de namespace que não seja local). Bem-vindo ao feio mundo do código clichê de comportamentos anexados.
usingSystem.Windows;usingSystem.Windows.Controls;usingSystem.Windows.Media;namespaceYourMainViewModelNameSpace{publicstaticclassDataGridTextBoxSingleClickEditBehavior{publicstaticreadonlyDependencyPropertyEnableProperty=DependencyProperty.RegisterAttached("Enable",typeof(bool),typeof(DataGridTextBoxSingleClickEditBehavior),newFrameworkPropertyMetadata(false,OnEnableChanged));publicstaticboolGetEnable(FrameworkElement frameworkElement){return(bool) frameworkElement.GetValue(EnableProperty);}publicstaticvoidSetEnable(FrameworkElement frameworkElement,boolvalue){
frameworkElement.SetValue(EnableProperty,value);}privatestaticvoidOnEnableChanged(DependencyObject d,DependencyPropertyChangedEventArgs e){if(d isDataGridCell dataGridCell)
dataGridCell.PreviewMouseLeftButtonDown+=DataGridCell_PreviewMouseLeftButtonDown;}privatestaticvoidDataGridCell_PreviewMouseLeftButtonDown(object sender,System.Windows.Input.MouseButtonEventArgs e){EditCell(sender asDataGridCell, e);}privatestaticvoidEditCell(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);}privatestatic T FindVisualParent<T>(UIElement element)where T :UIElement{var parent =VisualTreeHelper.GetParent(element)asUIElement;while(parent !=null){if(parent is T parentWithCorrectType)return parentWithCorrectType;
parent =VisualTreeHelper.GetParent(parent)asUIElement;}returnnull;}}}
Respostas:
Aqui está como resolvi esse problema:
Este DataGrid está vinculado a um CollectionViewSource (contendo objetos Person fictícios ).
A mágica acontece lá: DataGridCell.Selected = "DataGridCell_Selected" .
Simplesmente conecto o Evento Selecionado da célula DataGrid e chamo BeginEdit () no DataGrid.
Aqui está o código por trás do manipulador de eventos:
fonte
SelectionUnit
propriedade no DataGrid comoCell
.grd.BeginEdit(e)
, quero que o TextBox dessa célula tenha o foco. Como eu posso fazer isso? Eu tentei chamarFindName("txtBox")
o DataGridCell e o DataGrid, mas ele retornou null para mim.A resposta de Micael Bergeron foi um bom começo para eu encontrar uma solução que está funcionando para mim. Para permitir a edição com um único clique também para células na mesma linha que já estão no modo de edição, tive que ajustar um pouco. Usar o SelectionUnit Cell não era uma opção para mim.
Em vez de usar o evento DataGridCell.Selected, que só é disparado pela primeira vez em que uma célula da linha é clicada, usei o evento DataGridCell.GotFocus.
Se você fizer isso, você terá sempre a célula correta focada e no modo de edição, mas nenhum controle na célula estará focado, isso eu resolvi assim
fonte
De: http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing
XAML:
CÓDIGO POR TRÁS:
fonte
A solução de http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing funcionou muito bem para mim, mas eu a habilitei para cada DataGrid usando um estilo definido em um ResourceDictionary. Para usar manipuladores em dicionários de recursos, você precisa adicionar um arquivo code-behind a ele. Veja como você faz:
Este é um Dicionário de recursos DataGridStyles.xaml :
Observe o atributo x: Class no elemento raiz. Crie um arquivo de classe. Neste exemplo, seria DataGridStyles.xaml.cs . Coloque este código dentro de:
fonte
eu prefiro assim com base na sugestão de Dušan Knežević. você clica em e pronto))
fonte
Resolvi isso adicionando um gatilho que define a propriedade IsEditing de DataGridCell como True quando o mouse está sobre ele. Isso resolveu a maioria dos meus problemas. Também funciona com caixas de combinação.
fonte
Procuro editar célula em um único clique no MVVM e esta é uma outra maneira de fazer isso.
Adicionando comportamento no xaml
A classe EditCellOnSingleClickBehavior extend System.Windows.Interactivity.Behavior;
Voila!
fonte
Existem dois problemas com a resposta do usuário2134678. Um é muito pequeno e não tem efeito funcional. O outro é bastante significativo.
O primeiro problema é que o GotFocus está realmente sendo chamado contra o DataGrid, não o DataGridCell na prática. O qualificador DataGridCell no XAML é redundante.
O principal problema que encontrei com a resposta é que o comportamento da tecla Enter está quebrado. Enter deve mover você para a próxima célula abaixo da célula atual no comportamento normal do DataGrid. No entanto, o que realmente acontece nos bastidores é que o evento GotFocus será chamado duas vezes. Uma vez a célula atual perdendo o foco e outra vez a nova célula ganhando foco. Mas, enquanto BeginEdit for chamado na primeira célula, a próxima célula nunca será ativada. O resultado é que você tem edição com um clique, mas qualquer um que não esteja literalmente clicando na grade ficará incomodado, e um designer de interface de usuário não deve presumir que todos os usuários estão usando mouses. (Os usuários de teclado podem contornar isso usando Tab, mas isso ainda significa que eles estão se esforçando para não precisar fazer isso.)
Então, a solução para esse problema? Manipule o evento KeyDown para a célula e se a tecla for a tecla Enter, defina um sinalizador que impeça o BeginEdit de disparar na primeira célula. Agora a tecla Enter se comporta como deveria.
Para começar, adicione o seguinte estilo ao seu DataGrid:
Aplique esse estilo à propriedade "CellStyle" nas colunas para as quais deseja habilitar um clique.
Então, no código atrás, você tem o seguinte em seu manipulador GotFocus (observe que estou usando VB aqui porque é isso que nosso cliente de "solicitação de grade de dados com um clique" queria como linguagem de desenvolvimento):
Em seguida, você adiciona seu manipulador para o evento KeyDown:
Agora você tem um DataGrid que não mudou nenhum comportamento fundamental da implementação pronta para uso e ainda oferece suporte à edição com um único clique.
fonte
Sei que estou um pouco atrasado para a festa, mas tive o mesmo problema e encontrei uma solução diferente:
Como você pode ver, escrevi meu próprio DataGridTextColumn herdando tudo do DataGridBoundColumn. Substituindo o Método GenerateElement e retornando um controle Textbox ali mesmo, o Método para gerar o Elemento de Edição nunca é chamado. Em um projeto diferente, usei isso para implementar uma coluna Datepicker, então isso deve funcionar para caixas de seleção e comboboxes também.
Isso não parece afetar o comportamento do restante dos datagrids ... Pelo menos, não notei nenhum efeito colateral nem recebi feedback negativo até agora.
fonte
Atualizar
Uma solução simples se você concordar que sua célula permaneça uma caixa de texto (sem distinção entre o modo de edição e não edição). Desta forma, a edição com um único clique funciona imediatamente. Isso funciona com outros elementos como combobox e botões também. Caso contrário, use a solução abaixo da atualização.
Fim da atualização
Rant
Tentei tudo o que encontrei aqui e no google e até tentei criar minhas próprias versões. Mas cada resposta / solução funcionou principalmente para colunas de caixa de texto, mas não funcionou com todos os outros elementos (caixas de seleção, caixas de combinação, colunas de botões), ou mesmo quebrou essas outras colunas de elemento ou teve alguns outros efeitos colaterais. Obrigado microsoft por fazer o datagrid se comportar daquela maneira feia e nos forçar a criar esses hacks. Por isso decidi fazer uma versão que pode ser aplicada com um estilo a uma coluna de caixa de texto diretamente sem afetar as outras colunas.
Recursos
Fontes
Usei esta solução e a resposta de @my e modifiquei-os para um comportamento vinculado. http://wpf-tutorial-net.blogspot.com/2016/05/wpf-datagrid-edit-cell-on-single-click.html
Como usá-lo
Adicione este estilo. Isso
BasedOn
é importante quando você usa alguns estilos sofisticados para seu datagrid e não quer perdê-los.Aplique o estilo
CellStyle
a cada um de seusDataGridTextColumns
assim:E agora adicione esta classe ao mesmo namespace que seu MainViewModel (ou um namespace diferente. Mas então você precisará usar um outro prefixo de namespace que não seja
local
). Bem-vindo ao feio mundo do código clichê de comportamentos anexados.fonte
fonte