Dear All,

I have written some logic using MVVM pattern and tried to show a sub-datagrid in each row of a datagrid however there are some issues that I am currently facing and they are as follows (screenshot attached) :-

  1. In each row I have an expander in which I want to control the RowDetailsVisibilityMode of my sub datagrid.

  2. For selected checkboxes the rows should be deleted when clicked on Delete button at the end.

  3. Upon clicking of the Edit button, one can edit a particular row and again the rows become readonly.

Please suggest some approach on how to do this and kindly find my code as follows :-

View :-

<UserControl x:Class="WIMOProjectDemo.View.CustomerManagementModule"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:km="clr-namespace:WIMOProjectDemo.ViewModel"
             xmlns:prop="clr-namespace:WIMOProjectDemo.Properties"
             xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
             xmlns:interatComm="clr-namespace:InteractivityHelper"
             mc:Ignorable="d" 
             MinHeight="400" MinWidth="600">
    <UserControl.DataContext>
        <km:CustomerManagementModuleVM></km:CustomerManagementModuleVM>
    </UserControl.DataContext>
    <UserControl.Resources>
        <DataTemplate x:Key="SubGridData">
            <TabControl Width="Auto" Height="Auto" Margin="50,0,0,0">
                <TabItem Header="Other Contacts">
                    <DataGrid Width="Auto" Height="Auto" Background="AliceBlue" ItemsSource="{Binding SubGridData}" 
                              GridLinesVisibility="None">
                        <DataGrid.Columns>
                            <DataGridTextColumn Width="60" IsReadOnly="True" Header="Name" Binding="{Binding Path=Name}" />
                            <DataGridTextColumn Width="60" IsReadOnly="True" Header="Email" Binding="{Binding Path=Email}" />
                            <DataGridTextColumn Width="60" IsReadOnly="True" Header="Phone" Binding="{Binding Path=Phone}" />
                        </DataGrid.Columns>
                    </DataGrid>
                </TabItem>
                <TabItem Header="Billing Address">
                    <TextBlock Text="This is Billing Address" HorizontalAlignment="Center" VerticalAlignment="Center" />
                </TabItem>
                <TabItem Header="Delivery Address">
                    <DataGrid Width="Auto" Height="Auto" Background="DarkGoldenrod" ItemsSource="{Binding SubGridData}" 
                              GridLinesVisibility="None" >
                        <DataGrid.Columns>
                            <DataGridTextColumn Width="60" IsReadOnly="True" Header="Name" Binding="{Binding Path=Name}" />
                            <DataGridTextColumn Width="60" IsReadOnly="True" Header="Email" Binding="{Binding Path=Email}" />
                            <DataGridTextColumn Width="60" IsReadOnly="True" Header="Phone" Binding="{Binding Path=Phone}" />
                        </DataGrid.Columns>
                    </DataGrid>
                </TabItem>
                <TabItem Header="Other Information">
                    <TextBlock Text="This is Other Information" HorizontalAlignment="Center" VerticalAlignment="Center" />
                </TabItem>
            </TabControl>

        </DataTemplate>
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.10*"/>
            <RowDefinition Height="0.02*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="0.02*"/>
            <RowDefinition Height="0.10*"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0">
            <TextBox Margin="10,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center" Width="250" Height="25" 
                     x:Name="txt" Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}" />
        </Grid>
        <Grid Grid.Row="1">
            <TextBlock />
        </Grid>
        <Grid Grid.Row="2">
            <DataGrid x:Name="dgrd" ItemsSource="{Binding lstsource, UpdateSourceTrigger=PropertyChanged}" 
                      IsReadOnly="True" RowDetailsTemplate="{StaticResource SubGridData}" 
                      RowDetailsVisibilityMode="Collapsed" 
                      CanUserAddRows="True" RowBackground="LightBlue" AlternatingRowBackground="AliceBlue" 
                      HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" Background="Gainsboro" 
                      Width="Auto" Height="Auto" BorderThickness="10" UseLayoutRounding="True" CanUserDeleteRows="False" 
                      IsTextSearchEnabled="True" GridLinesVisibility="None" AutoGenerateColumns="False">
                <DataGrid.RowStyle>
                    <Style TargetType="{x:Type DataGridRow}">
                        <EventSetter Event="MouseDoubleClick" Handler="RowDoubleClick"/>
                    </Style>
                </DataGrid.RowStyle>
                <DataGrid.Columns>
                    <DataGridTemplateColumn>
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox x:Name="chkSelectRow" />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn>
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Button Command="{Binding Path=DataContext.DelegateCommandEdit, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" CommandParameter="{Binding ElementName=dgrd}">
                                    <Image Source="/WIMOProjectDemo;component/Images/edit icon.png"></Image>
                                </Button>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn>
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Expander x:Name="SubGridExpander">
                                    <!--<i:Interaction.Triggers>
                                        <i:EventTrigger EventName="Expanded">
                                            <interatComm:InteractiveCommand Command="{Binding DelegateCommandExpanded}"/>
                                        </i:EventTrigger>
                                        <i:EventTrigger EventName="Collapsed">
                                            <interatComm:InteractiveCommand Command="{Binding DelegateCommandCollapsed}"/>
                                        </i:EventTrigger>
                                    </i:Interaction.Triggers>-->
                                </Expander>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTextColumn MinWidth="75" IsReadOnly="True" Header="Customer" Binding="{Binding Path=Customer}" />
                    <DataGridTextColumn MinWidth="75" IsReadOnly="True" Header="Name" Binding="{Binding Path=Name}" />
                    <DataGridTextColumn MinWidth="75" IsReadOnly="True" Header="Access" Binding="{Binding Path=Access}" />
                    <DataGridTextColumn MinWidth="75" IsReadOnly="True" Header="Email" Binding="{Binding Path=Email}" />
                    <DataGridTextColumn MinWidth="75" IsReadOnly="True" Header="Phone" Binding="{Binding Path=Phone}" />
                    <DataGridTextColumn MinWidth="75" IsReadOnly="True" Header="Fax" Binding="{Binding Path=Fax}" />
                    <DataGridTextColumn MinWidth="75" IsReadOnly="True" Header="First" Binding="{Binding Path=First}" />
                    <DataGridTextColumn MinWidth="75" IsReadOnly="True" Header="Last" Binding="{Binding Path=Last}" />
                    <DataGridTextColumn MinWidth="75" IsReadOnly="True" Header="Country" Binding="{Binding Path=Country}" />
                    <DataGridTextColumn MinWidth="75" IsReadOnly="True" Header="Payment" Binding="{Binding Path=Payment}" />
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
        <Grid Grid.Row="3">
            <TextBlock />
        </Grid>
        <Grid Grid.Row="4">
            <Button x:Name="btnDeleteSelectedRows" Width="150" HorizontalAlignment="Left" VerticalAlignment="Center" 
                    Margin="15,0,0,0" Content="{x:Static prop:Resources.DeleteButtonText}" 
                    Command="{Binding Path=DelegateCommandDelete, RelativeSource={RelativeSource FindAncestor, 
                AncestorType={x:Type DataGrid}}}" CommandParameter="{Binding ElementName=dgrd}" />
        </Grid>
    </Grid>
</UserControl>

ViewModel :-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Windows.Input;
using System.Windows.Data;
using Microsoft.Practices.Prism.Commands;


namespace WIMOProjectDemo.ViewModel
{
    public class CustomerManagementModuleVM : INotifyPropertyChanged
    {
        #region Fields

        private ICollectionView _lstsource;

        private string _filterText;

        private DelegateCommand<DataGrid> _delegateCommandDelete;

        private DelegateCommand<DataGrid> _delegateCommandEdit;

        #endregion

        #region Public Variables

        public ObservableCollection<ChildGridClass> sublst;

        #endregion

        #region Properties

        public ICollectionView lstsource
        {
            get { return _lstsource; }
            set
            {
                _lstsource = value;
                OnPropertyChanged("lstsource");
            }
        }

        public string FilterText
        {
            get { return _filterText; }
            set
            {
                _filterText = value;
                OnPropertyChanged("FilterText");
                FilterCollection();
            }
        }

        #endregion

        #region Commands

        public DelegateCommand<DataGrid> DelegateCommandDelete
        {
            get
            {
                return this._delegateCommandDelete ?? new DelegateCommand<DataGrid>(FireMethod);
            }
        }

        public DelegateCommand<DataGrid> DelegateCommandEdit
        {
            get
            {
                return this._delegateCommandEdit ?? new DelegateCommand<DataGrid>(EditRowOnEditButton);
            }
        }

        #endregion

        #region Constructors

        public CustomerManagementModuleVM()
        {
            FillDataInGrid();
            lstsource = CollectionViewSource.GetDefaultView(ParentGridData);
            lstsource.Filter = new Predicate<object>(Filter);
        }

        #endregion

        #region Public Methods

        public bool Filter(object obj)
        {
            var data = obj as ParentGridClass;
            if (data != null)
            {
                if (!string.IsNullOrEmpty(_filterText))
                {
                    return data.Customer.Equals(_filterText) || data.Name.Equals(_filterText) || data.Access.Equals(_filterText) || data.Email.Equals(_filterText) || data.Phone.Equals(_filterText) || data.Fax.Equals(_filterText) || data.Country.Equals(_filterText) || data.Payment.Equals(_filterText);
                }
                return true;
            }
            return false;
        }

        public IEnumerable<ParentGridClass> ParentGridData
        {
            get
            {
                yield return new ParentGridClass { Customer = 324234, Name = "sgsfdd", Access = "Private", Email = "sdf@sfd.com", Phone = 56565, Fax = 45454, First = DateTime.Now.ToShortDateString(), Last = DateTime.Now.ToShortDateString(), Country = "India", Payment = "Card", SubGridData = sublst };
                yield return new ParentGridClass { Customer = 65464, Name = "bdcgdf", Access = "Public", Email = "dfgfg@sfd.com", Phone = 54646, Fax = 45443, First = DateTime.Now.ToShortDateString(), Last = DateTime.Now.ToShortDateString(), Country = "India", Payment = "Cheque", SubGridData = sublst };
                yield return new ParentGridClass { Customer = 53432, Name = "dsaf", Access = "Public", Email = "hg@sfd.com", Phone = 23423, Fax = 86786, First = DateTime.Now.ToShortDateString(), Last = DateTime.Now.ToShortDateString(), Country = "India", Payment = "Cash", SubGridData = sublst };
                yield return new ParentGridClass { Customer = 68767, Name = "ghgf", Access = "Private", Email = "sdf@sfd.com", Phone = 56785, Fax = 85464, First = DateTime.Now.ToShortDateString(), Last = DateTime.Now.ToShortDateString(), Country = "India", Payment = "Cheque", SubGridData = sublst };

                yield return new ParentGridClass { Customer = 345, Name = "ytryh", Access = "Private", Email = "fgdg@sfd.com", Phone = 54546, Fax = 89878, First = DateTime.Now.ToShortDateString(), Last = DateTime.Now.ToShortDateString(), Country = "Germany", Payment = "Card", SubGridData = sublst };
                yield return new ParentGridClass { Customer = 655, Name = "ret", Access = "Private", Email = "cvbcvb@sfd.com", Phone = 98797, Fax = 32433, First = DateTime.Now.ToShortDateString(), Last = DateTime.Now.ToShortDateString(), Country = "Germany", Payment = "Card", SubGridData = sublst };
                yield return new ParentGridClass { Customer = 234234, Name = "fghfgh", Access = "Public", Email = "dgdfsd@sfd.com", Phone = 67886, Fax = 56555, First = DateTime.Now.ToShortDateString(), Last = DateTime.Now.ToShortDateString(), Country = "Germany", Payment = "Cheque", SubGridData = sublst };
                yield return new ParentGridClass { Customer = 678678, Name = "cvxcv", Access = "Public", Email = "fdgfg@sfd.com", Phone = 56567, Fax = 45777, First = DateTime.Now.ToShortDateString(), Last = DateTime.Now.ToShortDateString(), Country = "Germany", Payment = "Card", SubGridData = sublst };

                yield return new ParentGridClass { Customer = 97887, Name = "vbnvn", Access = "Public", Email = "dfgh@sfd.com", Phone = 87990, Fax = 43555, First = DateTime.Now.ToShortDateString(), Last = DateTime.Now.ToShortDateString(), Country = "US", Payment = "Cash", SubGridData = sublst };
                yield return new ParentGridClass { Customer = 546, Name = "adsasd", Access = "Public", Email = "dfg@sfd.com", Phone = 87900, Fax = 43533, First = DateTime.Now.ToShortDateString(), Last = DateTime.Now.ToShortDateString(), Country = "US", Payment = "Card", SubGridData = sublst };
                yield return new ParentGridClass { Customer = 54677, Name = "uyiui", Access = "Public", Email = "sdfds@sfd.com", Phone = 65756, Fax = 56666, First = DateTime.Now.ToShortDateString(), Last = DateTime.Now.ToShortDateString(), Country = "US", Payment = "Card", SubGridData = sublst };
                yield return new ParentGridClass { Customer = 8977, Name = "qweqwe", Access = "Private", Email = "tyry@sfd.com", Phone = 98089, Fax = 34577, First = DateTime.Now.ToShortDateString(), Last = DateTime.Now.ToShortDateString(), Country = "US", Payment = "Cash", SubGridData = sublst };
            }
        }

        #endregion

        #region Private Methods

        private void FillDataInGrid()
        {
            sublst = new ObservableCollection<ChildGridClass>();
            sublst.Add(new ChildGridClass() { Name = "dsf", Email = "asd@dsa.com", Phone = 4566555 });
            sublst.Add(new ChildGridClass() { Name = "rty", Email = "fhg@dsa.com", Phone = 3243433 });
            sublst.Add(new ChildGridClass() { Name = "hjk", Email = "cvx@dsa.com", Phone = 9788887 });
            sublst.Add(new ChildGridClass() { Name = "qwe", Email = "ret@dsa.com", Phone = 2254884 });
        }

        private void FireMethod(DataGrid e)
        {
            ObservableCollection<ParentGridClass> lstsourceNew = lstsource as ObservableCollection<ParentGridClass>;
            for (int i = 0; i < e.Items.Count - 1; i++)
            {
                CheckBox x = e.Columns[0].GetCellContent(e.Items[i]) as CheckBox;
                if (x.IsChecked == true)
                {
                    MessageBox.Show(e.Items.Count.ToString());
                    lstsourceNew.RemoveAt(i);
                    lstsource = lstsourceNew as ICollectionView;
                    OnPropertyChanged("lstsource");
                }
            }
            MessageBox.Show("Deleted");
        }

        private void FilterCollection()
        {
            if (_lstsource != null)
            {
                _lstsource.Refresh();
            }
        }

        private void EditRowOnEditButton(DataGrid e)
        {
            OnPropertyChanged("lstsource");
            MessageBox.Show("Edited");
        }

        #endregion

        #region OnPropertyChangedEvent

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }

    #region Public Classes

    public class ParentGridClass
    {
        public int Customer { get; set; }
        public string Name { get; set; }
        public string Access { get; set; }
        public string Email { get; set; }
        public int Phone { get; set; }
        public int Fax { get; set; }
        public string First { get; set; }
        public string Last { get; set; }
        public string Country { get; set; }
        public string Payment { get; set; }
        public ObservableCollection<ChildGridClass> SubGridData { get; set; }
    }

    public class ChildGridClass
    {
        public string Name { get; set; }
        public string Email { get; set; }
        public int Phone { get; set; }
    }

    #endregion
}

xaml.cs :-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WIMOProjectDemo.View
{
    /// <summary>
    /// Interaction logic for CustomerManagementModule.xaml
    /// </summary>
    public partial class CustomerManagementModule : UserControl
    {
        public CustomerManagementModule()
        {
            InitializeComponent();
        }

        private void RowDoubleClick(object sender, RoutedEventArgs e)
        {
            var row = (DataGridRow)sender;
            row.DetailsVisibility = row.DetailsVisibility == Visibility.Collapsed ?
                Visibility.Visible : Visibility.Collapsed;
        }
    }
}

Recommended Answers

All 6 Replies

Well, you need to bind your checkbox to something like an MarkForDelete on the thing you want to delete. When you click on Delete, iterate through all the data and filter out based on this flag. Delete as required.

On the last point, you could set your datagrid into edit mode when you click, then pick up the OnKeyPressed event and check for the Return key, or any mouseclick outside the control.

hi Ketsuekiame,

Could you please ellaborate by giving some code snippets or adding to my code ?

I am done with the expander and edit button functionalities (point numbers 1 and 3) however I'm still struggling with the checkbox thing. Could someone please help me out of this ?

Can someone please help me ???

Not exactly sure what you're struggling with...Bind the checkbox to a boolean on your model and check the result when you save.

Hi,

I found the solution on my own but thanks for the suggestions anyways, they may help me in the future :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.