We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date
close icon

Create automatically a new row after an entry in combo box was selected

Hi,

I don't know how to achieve the following scenario:
  1. I need a DataGrid with a data source with the four columns ItemName, ItemType, Value and ValueType  -  DONE.
  2. The column ItemType should hidden. It contains only the values "regular" or "nonregular"  -  DONE.
  3. The records with ItemType = "regular", can't edit column ValueType  -  DONE.
  4. The records with ItemType = "nonregular", can/must select ValueType in a combo box  -  DONE.
  5. After editing a ValueType, a new row for the same Item (ItemName, ItemType) should be created (as direct successor row)  -  TO DO!

Please have a look to the attached screenshots.
  • screenshot1: The empty DataGrid, where you can see Testitem3 and Testitem7 with data property ItemType = "nonregular"
  • screenshot2: Entered values in row 1, 2 and 3
  • screenshot3: Entered ValueType in row 3
  • screenshot4: After the entered ValueType in row 3 a new row with Testitem3 should be created as a direct successor
  • screenshot5: Each time a ValueType is entered, a new row should be created. So, that there is everytime an empty line to insert a Value and a ValueType.
  • screenshot6: Of course every "nonregular" item can have more than one row, as you can see on Testitem3 and Testitem7.

I've also attached a sample solution, where you can explore the behavior (of course without the creation of new rows).

I've tried a lot of ideas. But nothing works. Are you able to help me?

Regards

Harald


Attachment: SfGridSample1_63287b8.zip

8 Replies

JG Jai Ganesh S Syncfusion Team November 4, 2016 12:54 PM UTC

Hi Harald, 
You can achieve your requirement for adding a new row while we selecting the combo box item by using CellTemplateSelector and RecordPropertyChanged event like below, 
private void SampleDataGrid_AutoGeneratingColumn(object sender, AutoGeneratingColumnArgs e) 
{ 
    // this column should not be displayed 
    e.Cancel = e.Column.MappingName == "ItemType"; 
 
    // this column should not be editable 
    e.Column.AllowEditing = e.Column.MappingName == "Value"; 
 
    // this column should contain comboboxes, when Property "ItemType" is "nonregular" 
    if (e.Column.MappingName == "ValueType") 
    { 
        e.Column.CellTemplateSelector = new DataTemplateSelectorExt(); 
        return; 
    } 
} 
 
public class DataTemplateSelectorExt : DataTemplateSelector 
{ 
    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
        if (item == null || container == null) 
            return base.SelectTemplate(item, container); 
 
        if ((item as DataItem).ItemType != "nonregular") 
        { 
            var factory1 = new FrameworkElementFactory(typeof(TextBlock)); 
            factory1.SetValue(TextBlock.TextProperty, "<default>"); 
            factory1.SetValue(TextBlock.OpacityProperty, 0.2); 
            return new DataTemplate { VisualTree = factory1 }; 
        } 
        else 
        { 
            var dataGrid = Application.Current.MainWindow.FindName("SampleDataGrid") as SfDataGrid; 
            var factory2 = new FrameworkElementFactory(typeof(ComboBox)); 
            factory2.SetBinding(ComboBox.ItemsSourceProperty, new Binding { Source = ((dataGrid)?.DataContext as SampleViewModel)?.ValueTypeSource }); 
            factory2.SetValue(ComboBox.SelectedValuePathProperty, "Id"); 
            factory2.SetValue(ComboBox.DisplayMemberPathProperty, "TypeName"); 
            factory2.SetBinding(ComboBox.SelectedValueProperty, new Binding("ValueType") { Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); 
            var trigger2 = new DataTrigger { Binding = new Binding("ItemType"), Value = "nonregular" }; 
            return new DataTemplate { VisualTree = factory2 }; 
        } 
        return base.SelectTemplate(item, container); 
    } 
} 
 
 
 
private void SampleDataGrid_Loaded(object sender, RoutedEventArgs e) 
{ 
    if(this.SampleDataGrid.View  != null) 
        this.SampleDataGrid.View.RecordPropertyChanged += View_RecordPropertyChanged; 
} 
 
private void View_RecordPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
{ 
    var rowIndex = this.SampleDataGrid.ResolveToRowIndex((sender as DataItem)); 
             
    (this.SampleDataGrid.DataContext as SampleViewModel).GridDataSource.Insert(rowIndex, sender as DataItem); 
} 
 
Regards, 
Jai Ganesh S 



HB Harald Betzler November 4, 2016 01:55 PM UTC

Hi Jai,

thank you for the transformation into DataTemplateSelector. That is much more clearly arranged.

And many thanks for the solution to copy grid rows.

I've changed
GridDataSource.Insert(rowIndex, sender as DataItem);
to
var sourceItem = sender as DataItem;
var targetItem = new DataItem {ItemName = sourceItem.ItemName, ItemType = sourceItem.ItemType};
GridDataSource.Insert(rowIndex, targetItem);
to get a new row with a new DataItem as a copy of the old DataItem. 
Otherwise the same DataItem was displayed two times. With the effect of changing both rows while editing one row.

Regards

Harald


JG Jai Ganesh S Syncfusion Team November 7, 2016 05:51 AM UTC

Hi Harald, 
Thank you for the update. 
Please let us know if you need further assistance on this. 
Regards, 
Jai Ganesh S 



HB Harald Betzler November 9, 2016 01:29 PM UTC

Hi Jai,

while transfering the solution from the sample to my real project, I've realized, that (due to MVVM concerns) I do not have a definition of DataItem in my view.

I think, I have to insert the new row in my viewmodel. But how can I get the record index in code behind (to send it via mvvm light messenger to the viewmodel).

ResolveToRowIndex needs a DataItem:
var rowIndex = CostPlanningGrid.ResolveToRowIndex(sender as DataItem);
Do you have a solution?

Regards

Harald




HB Harald Betzler November 9, 2016 03:04 PM UTC

Hi Jai,

I've seen, that everytime when the selected combobox item will be changed, a new row will be added. 

That's not the expected behavior. Only when the combobox wil be changed from "nothing selected" to a selected value, a new row should be inserted.

Or with other words: Everytime there should be exactly one row for each item (with ItemType = "nonregular") with an empty ValueType.

Regards

Harald


JG Jai Ganesh S Syncfusion Team November 10, 2016 07:12 AM UTC

Hi Harald, 
Please find the response for your queries as below, 
Query 1: 
We have modified our sample to add the record through RecordPropertyChanged event in MVVM pattern using Behavior, 
  <Syncfusion:SfDataGrid    
            x:Name="SampleDataGrid"  
            ColumnSizer="AutoWithLastColumnFill" 
            Margin="10" 
            ItemsSource="{Binding GridDataSource}" 
            EditTrigger="OnTap" 
            AutoGenerateColumns="True"> 
 
            <interactivity:Interaction.Behaviors> 
                <local:InitialSetupBehaviour/> 
            </interactivity:Interaction.Behaviors> 
 </Syncfusion:SfDataGrid> 
 
Query 2: 
You can achieve your requirement for adding the new row with ItemType = "nonregular" and an empty ValueType. 
List<string> list = new List<string>(); 
        private void View_RecordPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
        { 
            var rowIndex = this.AssociatedObject.ResolveToRowIndex((sender as DataItem)); 
            var data = (sender as DataItem); 
 
            if (!list.Contains(data.ItemName)) 
            { 
                (this.AssociatedObject.DataContext as SampleViewModel).GridDataSource.Insert(rowIndex, data); 
                list.Add(data.ItemName); 
            } 
        } 
 
Regards, 
Jai Ganesh S 



HB Harald Betzler November 10, 2016 12:13 PM UTC

Hi Jai,

thanks for your response.

Your Suggestion to Query1:

This is also not a valid solution due to MVVM concerns. Because the code behind is moved to the ViewModel. But the ViewModel now knows about View details (e.g. grids, columns, comboboxes, events, ...). 

The better way would be to enable the eventhandler View_RecordPropertyChanged to get the data without casting to a class defined in the model. So the data could be sent to ViewModel via Messenger and the rest of data handling will be done there.

For example in Grid_CurrentCellValidated I'm able to read the data in a comfort way:
    var id = e.RowData.GetType().GetProperties().Single(pi => pi.Name.Equals("Id")).GetValue(e.RowData, null);

But in View_RecordPropertyChanged I've no idea to get the data from sender or PropertyChangedEventArgs.

Do you have any ideas to read the data without casting them to a model based entity?


Your Suggestion to Query2:

This is also not workable, because the list with the created items lives only until applications end. After the next application start the list will be empty.

I expected a idea to get e.OldValue and e.NewValue in View_RecordPropertyChanged eventhandler like in Grid_CurrentCellValidated
Then a new record will be inserted only when the old value was NULL.

Is there a possibility to get the old value?


Regards

Harald







JG Jai Ganesh S Syncfusion Team November 13, 2016 05:23 PM UTC

Hi Harald, 
 
Query 1: 
 
You can achieve your requirement for read the data without casting them to a model based entity like CurrentCellValidated event, 
 
private void View_RecordPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
        { 
            var id = sender.GetType().GetProperties().Single(pi => pi.Name.Equals("ItemName")).GetValue(sender, null); 
 
        } 
 
Query 2: 
 
We regret to inform you that, the e.OldValue and e.NewValue are not in  View_RecordPropertyChanged eventhandler like in Grid_CurrentCellValidated. Could you please maintain the list for adding a new row with ItemType = "nonregular" and an empty ValueType in  your application. 
 
Regards, 
Jai Ganesh S 


Loader.
Live Chat Icon For mobile
Up arrow icon