WPF DataGrid Single Click to create a new item

I have a DataGrid with a DataGridTemplateColumn and a ComboBox in it.

 <DataGrid GridLinesVisibility="All" AutoGenerateColumns="False" ItemsSource="{Binding TestItemCollection}"> <DataGrid.Columns> <DataGridTemplateColumn Width="*" Header="Test Column"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ComboBox Width="150" HorizontalAlignment="Left" ItemsSource="{Binding TestChildCollection}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> public ObservableCollection<TestClass> TestItemCollection { get; set; } = new ObservableCollection<TestClass> { new TestClass(), new TestClass(), new TestClass(), }; public class TestClass { public ObservableCollection<string> TestChildCollection { get; set; } = new ObservableCollection<string> { "First test item", "Second test item" , "Third test item" , "Fourth test item" }; } 

When I click on a ComboBox in an empty line, it does not seem to create a new instance of my collection and only gives an empty list.

enter image description here

I need to double click on the empty row space.

enter image description here

And only then I will receive data in ComboBox .

enter image description here

How can I get data in a ComboBox one click on an empty line?

+5
source share
2 answers

If you need to get data into a ComboBox one click on an empty line, I suggest you use Caliburn.Micro to β€œattach” the command to the DropDownOpened event of your ComboBox .

Here's a sample: primarily XAML

 <Window x:Class="WpfApplication1.MainView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:cal="http://www.caliburnproject.org" Title="MainView" Height="600" Width="600" Name="_window"> <DataGrid GridLinesVisibility="All" AutoGenerateColumns="False" ItemsSource="{Binding TestItemCollection}"> <DataGrid.Columns> <DataGridTemplateColumn Width="*" Header="Test Column"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ComboBox Width="150" HorizontalAlignment="Left" ItemsSource="{Binding TestChildCollection}" cal:Message.Attach="[Event DropDownOpened] = [Action Choose($dataContext)]"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> 

Then ViewModel:

 public class MainViewModel : Caliburn.Micro.PropertyChangedBase { public MainViewModel() { TestItemCollection = new ObservableCollection<TestClass> { new TestClass(), new TestClass(), new TestClass(), }; } public void Choose(object data) { if (!(data is TestClass)) { TestItemCollection.Add(new TestClass()); } } public ObservableCollection<TestClass> TestItemCollection { get; set; } } 

Please note that in my example, the TestClass code TestClass same as the one you wrote. Of course, you must configure the application to work with Caliburn.Micro (if you do not know how to do this, you can read the documentation ).

If you don't want (or maybe can't) use Caliburn.Micro, you can get the same result using System.Windows.Interactivity (see my edit below).

Try the code: just a click and a new line is automatically created. Hope this helps you.

EDIT: Alternative Solution with System.Windows.Interactivity

If you cannot use Caliburn.Micro, you just need to modify the MainView XAML in this way:

 <Window x:Class="WpfApplication1.MainView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" Title="MainView" Height="600" Width="600" Name="_window"> <DataGrid GridLinesVisibility="All" AutoGenerateColumns="False" ItemsSource="{Binding TestItemCollection}"> <DataGrid.Columns> <DataGridTemplateColumn Width="*" Header="Test Column"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ComboBox Width="150" HorizontalAlignment="Left" ItemsSource="{Binding TestChildCollection}"> <i:Interaction.Triggers> <i:EventTrigger EventName="DropDownOpened"> <ei:CallMethodAction MethodName="ChooseWithInteraction" TargetObject="{Binding ElementName=_window, Path=DataContext}" /> </i:EventTrigger> </i:Interaction.Triggers> </ComboBox> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> </Window> 

As you can see, I just added links to the Microsoft.Expression.Interactions and System.Windows.Interactivity libraries. Then I added EventTrigger and CallMethodAction to the ComboBox .

Now in MainViewModel you can replace the Choose method with ChooseWithInteraction one (of course, you can also just add it to the code):

 public void ChooseWithInteraction(object sender, EventArgs args) { object data = ((ComboBox)sender).DataContext; if (!(data is TestClass)) { TestItemCollection.Add(new TestClass()); } } 

That way you can get the same behavior of my first solution, but without using Caliburn.

+1
source

I came up with a solution that you can achieve the desired functionality by following these two steps.

Step one. . You must specify the CellEditingTemplate for the DataGridTemplateColumn and set IsHitTestVisible to false for the DataGridTemplateColumn.CellTemplate . This will force the user interface to enter edit mode when the DataGridCell button is pressed (for example, your ComboBox ), and as a result, a new instance of your collection will be created. To do this, you first need to define a property in TestClass to save the selected value for each ComboBox :

 public class TestClass { public ObservableCollection<string> TestChildCollection { get; set; } // keeps the selected value of each ComboBox public string SelectedTestItem { get; set; } public TestClass() { TestChildCollection = new ObservableCollection<string> {"First test item", "Second test item" , "Third test item" , "Fourth test item" }; } } 

Then the xaml for your DataGrid should change as follows:

  <DataGrid Grid.Row="0" SelectionUnit="Cell" DataGridCell.Selected="DataGridCell_GotFocus" GridLinesVisibility="All" AutoGenerateColumns="False" ItemsSource="{Binding TestItemCollection}"> <DataGrid.Columns> <DataGridTemplateColumn Width="*" Header="Test Column"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ComboBox Width="150" IsHitTestVisible="False" HorizontalAlignment="Left" ItemsSource="{Binding TestChildCollection}" SelectedItem="{Binding SelectedTestItem}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <ComboBox Width="150" HorizontalAlignment="Left" ItemsSource="{Binding TestChildCollection}" SelectedItem="{Binding SelectedTestItem}"/> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> 

Step Two: As you can see in the above xaml , SelectionUnit set to Cell , as well as an event handler for DataGridCell.Selected . The code for the event handler is as follows:

  private void DataGridCell_GotFocus(object sender, RoutedEventArgs e) { if (e.OriginalSource.GetType() == typeof(DataGridCell)) { DataGrid dataGrid = (DataGrid)sender; dataGrid.BeginEdit(e); } } 

This ensures that every time you click on a DataGridCell , it goes into edit mode. so you need to click once each time you try to open a ComboBox inside a newly created DataGridRow .

+1
source

Source: https://habr.com/ru/post/1233772/


All Articles