Datagrid load list of items for particular columns

Kran2022 381 Reputation points
2023-02-06T08:41:02.56+00:00

Hi All, Morning:

I'm reading a xml file to display it in the datagridview then save it back to the file after editing. My issue here, that i have a 3 list string properties From, Price & ServiceFee see below products class code, where i couldnt read these 3 list properties from the xml file and save it back to the xml file.

How can i read those 3 list properties read, display & save it back to the file? without creating a new class. Thanks for your help/time.

View Method:

 
case "ReadPricing": //to read local pricing file
ProductPriceList = GetProductsPriceList();
View = CollectionViewSource.GetDefaultView(ProductPriceList);
View.Filter = Filter;
View.Refresh();
return;


private ObservableCollection<Products> productpricelist;

public ObservableCollection<Products> ProductPriceList
{
	get { return productpricelist; }
	set
	{
		productpricelist = value;
		OnPropertyChanged("ProductPriceList");
	}
}

Method to read XML content: got stuck how to read lsit of FromQuantity, Price & ServiceFee

 private ObservableCollection<Products> GetProductsPriceList() //to read xml file contents 
        {
            var products = new ObservableCollection<Products>();
          
            using (Stream str = new FileStream(FilePath, FileMode.Open))
            {
                XElement xe0 = XElement.Load(str);
                foreach (var xe1 in xe0.Descendants("Products").Elements())
                {

                    var p = new Products
                    {
                        SysId = xe1.Attribute("Sys_Oid").Value,
                        Mainproduct = xe1.Name.ToString(),
                        Name = xe1.Attribute("Name").Value,
                        Visible = xe1.Descendants("ProductVisibility").FirstOrDefault().Attribute("Visible").Value,
                        Price = xe1.Descendants("ProductPrice").FirstOrDefault().Attribute("Price").Value,  
                        From = xe1.Descendants("ProductPrice").FirstOrDefault().Attribute("FromQuantity").Value,
                        ServiceFee = xe1.Descendants("ProductPrice").FirstOrDefault().Attribute("ServiceFee").Value,
                        NameIcon = xe1.Attribute("DefaultIconName")?.Value
                       
                    };

                    products.Add(p);

                    
                }
            }
            return products;
        }

Method to save XML content: got stuck how to update the list of FromQuantity, Price & ServiceFee

private void Execute(object parm) // method to save back to xml file from datagrid 
{

	XmlDocument doc = new XmlDocument();
	doc.Load(@"C:\xmltest\26112023.txt");
	foreach (Products pp in productpricelist)
	{
		pp.Name = RenameToCentiMeters(pp.Name); //put it back to cm to store in the file
		OnPropertyChanged(nameof(ProductPriceList));

		string replacecomma = pp.Price;
		pp.Price = replacecomma.Replace(",", "."); //put it back to dot instead of comma
		OnPropertyChanged(nameof(ProductPriceList));

		foreach (XmlElement pn in doc.SelectNodes("/Data/Products/*"))
		{
			
			if (pp.SysId == pn.GetAttribute("Sys_Oid").ToString()) //reference id comparison 
			 {
				
				foreach (XmlNode visibility in pn.SelectNodes("Visibilities"))
				{
					foreach (XmlNode productVisibilty in visibility.SelectNodes("ProductVisibility"))
					{
						productVisibilty.Attributes["Visible"].InnerText = pp.Visible;

						foreach (XmlNode price in productVisibilty.SelectNodes("Prices"))
						{
							foreach (XmlNode productPrice in price.SelectNodes("ProductPrice"))
							{
								productPrice.Attributes["FromQuantity"].InnerText = pp.From;
								productPrice.Attributes["Price"].InnerText = pp.Price;
								productPrice.Attributes["ServiceFee"].InnerText = pp.ServiceFee;
							}
						}

					}

				}
			 }
		}
	}
	doc.Save(@"C:\xmltest\26112023_.txt");
   

}

Class Products:


 public class Products
    {

        string sysid;
        string mainproduct;
        string name;
        string visible;
        string nameicon;


        public string SysId
        {
            get { return sysid; }
            set { sysid = value; }
        }

        public string Mainproduct
        {
            get { return mainproduct; }
            set { mainproduct = value; }
        }
		
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

          public string Visible
        {
            get { return visible; }
            set 
            { 
                visible = value;
               
            }
        }

        private List<string> fromqty = new List<string>();
        public List<string> FromQuantity
        {
            get { return fromqty; }
            set { fromqty = value; }
        }

        private List<string> price = new List<string>();
        public List<string> Price
        {
            get { return price; }
            set { price = value; }
        }

        private List<string> servicefee = new List<string>();
        public List<string> ServiceFee
        {
            get { return servicefee; }
            set { servicefee = value; }
        }



   
        public string NameIcon
        {
            get { return nameicon; }
            set { nameicon = value; }
        }
    }

Renametoinches method:

      public static string RenameToCentiMeters(string inches)
        {
            var dic = GetInchesToCentimetersPairs();
            foreach (var pair in dic.OrderByDescending(x => x.Key.Length))
            {
                inches = inches.Replace(pair.Key, pair.Value);
            }
            return inches;
        }

       private static Dictionary<string, string> GetInchesToCentimetersPairs()
        {
            var dic = new Dictionary<string, string>();
            dic.Add("2x4", "5x10");
            dic.Add("2x4/8", "5x10/20"); 
           
            return dic;
        }

Datagridview:


            <DataGrid  x:Name="datagrid" HorizontalAlignment="Left" SelectedItem="{Binding SelectedProduct, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        SelectionMode="Single" SelectionUnit="FullRow"  Width="Auto" 
            ItemsSource="{Binding View}" AutoGenerateColumns="False" CanUserAddRows="False" ScrollViewer.VerticalScrollBarVisibility="Visible" Margin="0,2,0,-2"  
                            Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type DockPanel}}, Path=ActualHeight}" >

                <DataGrid.Columns>
                    <DataGridTextColumn Header="SystemPriceID" Binding="{Binding SysId}" Width="*" IsReadOnly="True"/>
                    <DataGridTextColumn Header="MianProduct"   Binding="{Binding Mainproduct}" Width="*" IsReadOnly="True"/>
                    <DataGridTextColumn Header="Name"   Binding="{Binding Name}" Width="*" IsReadOnly="True"/>
                        
                        <DataGridTemplateColumn Header="Visible"  Width="100" >
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <CheckBox IsChecked="{Binding Visible, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                       
                    <DataGridTemplateColumn Header="FromQuantity" Width="100">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBox Text="{Binding From,StringFormat='c',UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" PreviewTextInput="OnPreviewTextInput"  />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>

                        <DataGridTemplateColumn Header="Price" Width="60">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBox Text="{Binding Price,StringFormat='c',UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" PreviewTextInput="OnPreviewTextInput"  />
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>

                        <DataGridTemplateColumn Header="ServiceFee" Width="100">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBox Text="{Binding ServiceFee,StringFormat='c',UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" PreviewTextInput="OnPreviewTextInput"  />
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>

                        <DataGridTemplateColumn Header="Add"  Width="*" IsReadOnly="True">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <Button >Add</Button>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>

                    <DataGridTemplateColumn Header="Remove"  Width="*" IsReadOnly="True">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Button >Remove</Button>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,670 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,233 questions
{count} votes

Accepted answer
  1. Peter Fleischer (former MVP) 19,231 Reputation points
    2023-02-10T09:53:19.66+00:00

    Hi,
    please, try my demo with your data. Please, for additional, new or extended questions use new thread!

    <Window x:Class="WpfApp1.Window042"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp042"
            mc:Ignorable="d"
            Title="Kran2022_230207" Height="450" Width="800">
      <Window.DataContext>
        <local:ProductPriceViewModel/>
      </Window.DataContext>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="2*"/>
          <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <DataGrid x:Name="datagrid"
                  ItemsSource="{Binding View}" AutoGenerateColumns="False">
          <DataGrid.Columns>
            <DataGridTextColumn Header="SystemPriceID" Binding="{Binding SysId}" Width="*" IsReadOnly="True"/>
            <DataGridTextColumn Header="MianProduct"   Binding="{Binding Mainproduct}" Width="*" IsReadOnly="True"/>
            <DataGridTextColumn Header="Name"   Binding="{Binding Name}" Width="*" IsReadOnly="True"/>
    
            <DataGridTemplateColumn Header="Visible"  Width="100" >
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <CheckBox IsChecked="{Binding Visible, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
    
            <DataGridTemplateColumn Header="Add"  Width="*" IsReadOnly="True">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <Button>Add</Button>
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
    
            <DataGridTemplateColumn Header="Remove" Width="*" IsReadOnly="True">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <Button>Remove</Button>
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
          </DataGrid.Columns>
        </DataGrid>
        <Button Grid.Row="1" Content="Load" Width="100" Margin="10" HorizontalAlignment="left"
                Command="{Binding Cmd}" CommandParameter="Load"/>
        <Button Grid.Row="1" Content="Clear" Width="100" Margin="10" HorizontalAlignment="Center"
                Command="{Binding Cmd}" CommandParameter="Clear"/>
        <Button Grid.Row="1" Content="Save" Width="100" Margin="10" HorizontalAlignment="Right"
                Command="{Binding Cmd}" CommandParameter="Save"/>
        <Grid Grid.Column="1" DataContext="{Binding ElementName=datagrid, Path=SelectedItem}">
          <DataGrid ItemsSource="{Binding Prices}" AutoGenerateColumns="False" Margin="10">
            <DataGrid.Columns>
              <DataGridTextColumn Header="FromQuantity" Binding="{Binding FromQuantity}"/>
              <DataGridTextColumn Header="Price" Binding="{Binding Price}"/>
              <DataGridTextColumn Header="ServiceFee" Binding="{Binding ServiceFee}"/>
            </DataGrid.Columns>
          </DataGrid>
        </Grid>
      </Grid>
    </Window>
    
    
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Xml;
    using System.Xml.Linq;
    
    namespace WpfApp042
    {
    	class ProductPriceViewModel : INotifyPropertyChanged
    	{
    
    		// ctor
    		public ProductPriceViewModel() => ProductPriceList = new ObservableCollection<Products>();
    
    		// Path of xml file
    		public string FilePath { get; set; } = @"Window041XML.txt";
    
    		// View member
    		private CollectionViewSource cvs = new CollectionViewSource();
    		public ICollectionView View { get => cvs.View; }
    
    		private ObservableCollection<Products> _productPriceList;
    		private ObservableCollection<Products> ProductPriceList
    		{
    			get => this._productPriceList;
    			set
    			{
    				this._productPriceList = value;
    				cvs.Source = value;
    				OnPropertyChanged(nameof(View));
    			}
    		}
    
    		// Commands
    		public ICommand Cmd { get => new RelayCommand(executemethod, canexecutemethod); }
    
    		private void executemethod(object obj)
    		{
    			switch (obj.ToString())
    			{
    				case "Save":
    					SaveProductsPriceList();
    					break;
    				case "Clear":
    					ProductPriceList.Clear();
    					break;
    				case "Load":
    					ProductPriceList = GetProductsPriceList();
    					break;
    				default:
    					break;
    			}
    		}
    		private static bool canexecutemethod(object obj) => true;
    
    		private XmlDocument productDoc;
    
    #pragma warning disable CS8601 // Dereference of a possibly null reference.
    #pragma warning disable CS8602 // Dereference of a possibly null reference.
    		private ObservableCollection<Products> GetProductsPriceList() //to read xml file contents 
    		{
    			var products = new ObservableCollection<Products>();
    			productDoc = new XmlDocument();
    			productDoc.Load(FilePath);
    			XElement xe0 = XElement.Parse(productDoc.InnerXml);
    			foreach (var xe1 in xe0.Descendants("Products").Elements())
    			{
    				var p = new Products
    				{
    					SysId = xe1.Attribute("Sys_Oid")?.Value,
    					Mainproduct = xe1.Name.ToString(),
    					Name = xe1.Attribute("Name")?.Value,
    					Visible = xe1.Descendants("ProductVisibility")?.FirstOrDefault().Attribute("Visible")?.Value,
    					NameIcon = xe1.Attribute("DefaultIconName")?.Value
    				};
    				foreach (XElement xe2 in xe1.Descendants("ProductPrice"))
    				{
    					p.Prices.Add(new PriceDetail()
    					{
    						Sys_Oid = xe2.Attribute("Sys_Oid")?.Value,
    						Price = xe2.Attribute("Price")?.Value,
    						FromQuantity = xe2.Attribute("FromQuantity")?.Value,
    						ServiceFee = xe2.Attribute("ServiceFee").Value
    					});
    				}
    				products.Add(p);
    			}
    			return products;
    		}
    
    		private void SaveProductsPriceList() //to save xml fiel contents 
    		{
    			foreach (XmlElement pn in productDoc.SelectNodes("/Data/Products/*"))
    			{
    				Products pp = ProductPriceList.Where(p => p.SysId == pn.GetAttribute("Sys_Oid")?.ToString()).FirstOrDefault();
    				if (pp != null)
    				{
    					foreach (XmlNode visibility in pn.SelectNodes("Visibilities"))
    					{
    						foreach (XmlNode productVisibilty in visibility.SelectNodes("ProductVisibility"))
    						{
    							productVisibilty.Attributes["Visible"].InnerText = pp.Visible;
    							foreach (XmlNode price in productVisibilty.SelectNodes("Prices"))
    							{
    								foreach (XmlNode productPrice in price.SelectNodes("ProductPrice"))
    								{
    									PriceDetail pd = pp.Prices.Where(p => p.Sys_Oid == productPrice.Attributes["Sys_Oid"]?.Value.ToString()).FirstOrDefault();
    									if (pd != null)
    									{
    										productPrice.Attributes["FromQuantity"].InnerText = pd.FromQuantity;
    										productPrice.Attributes["Price"].InnerText = pd.Price;
    										productPrice.Attributes["ServiceFee"].InnerText = pd.ServiceFee;
    									}
    								}
    							}
    
    						}
    					}
    				}
    			}
    			productDoc.Save(FilePath);
    		}
    
    		public static string RenameToCentiMeters(string inches)
    		{
    			var dic = GetInchesToCentimetersPairs();
    			foreach (var pair in dic.OrderByDescending(x => x.Key.Length))
    				inches = inches.Replace(pair.Key, pair.Value);
    			return inches;
    		}
    
    		private static Dictionary<string, string> GetInchesToCentimetersPairs()
    		{
    			var dic = new Dictionary<string, string>();
    			dic.Add("2x4", "5x10");
    			dic.Add("2x4/8", "5x10/20");
    			return dic;
    		}
    
    		// INotifyPropertyChanged
    #pragma warning disable CS8612 // Nullability of reference types in type doesn't match implicitly implemented member.
    		public event PropertyChangedEventHandler PropertyChanged;
    		public void OnPropertyChanged([CallerMemberName] string info = "") =>
    				PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
    	}
    
    	//#pragma warning disable CS8603 // Dereference of a possibly null reference.
    	public class Products
    	{
    		public string SysId { get; set; }
    		public string Mainproduct { get; set; }
    		public string Name { get; set; }
    		public string Visible { get; set; }
    		public string From { get; set; }
    		public List<PriceDetail> Prices { get; set; } = new List<PriceDetail>();
    		public string NameIcon { get; set; }
    	}
    
    	public class PriceDetail
    	{
    		public string Sys_Oid { get; set; }
    		public string FromQuantity { get; set; }
    		public string Price { get; set; }
    		public string ServiceFee { get; set; }
    	}
    
    #pragma warning disable CS8767 // Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes).
    #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
    	public class RelayCommand : ICommand
    	{
    		private readonly Predicate<object> _canExecute;
    		private readonly Action<object> _action;
    		public RelayCommand(Action<object> action) { _action = action; _canExecute = null; }
    		public RelayCommand(Action<object> action, Predicate<object> canExecute) { _action = action; _canExecute = canExecute; }
    		public void Execute(object o) => _action(o);
    		public bool CanExecute(object o) => _canExecute == null ? true : _canExecute(o);
    		public event EventHandler CanExecuteChanged
    		{
    			add { CommandManager.RequerySuggested += value; }
    			remove { CommandManager.RequerySuggested -= value; }
    		}
    	}
    }
    

    Result:

    x

    1 person found this answer helpful.
    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,231 Reputation points
    2023-02-07T06:01:47.9266667+00:00

    Hi,
    your posted code is inconsistent. I changed your code a little bis and it works correct:

    <Window x:Class="WpfApp1.Window041"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp041"
            mc:Ignorable="d"
            Title="Kran2022_230206" Height="450" Width="800">
      <Window.DataContext>
        <local:ProductPriceViewModel/>
      </Window.DataContext>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <DataGrid ItemsSource="{Binding View}" AutoGenerateColumns="False">
          <DataGrid.Columns>
            <DataGridTextColumn Header="SystemPriceID" Binding="{Binding SysId}" Width="*" IsReadOnly="True"/>
            <DataGridTextColumn Header="MianProduct"   Binding="{Binding Mainproduct}" Width="*" IsReadOnly="True"/>
            <DataGridTextColumn Header="Name"   Binding="{Binding Name}" Width="*" IsReadOnly="True"/>
    
            <DataGridTemplateColumn Header="Visible"  Width="100" >
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <CheckBox IsChecked="{Binding Visible, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
    
            <DataGridTemplateColumn Header="FromQuantity" Width="100">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <TextBox Text="{Binding From,StringFormat='c',UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
    
            <DataGridTemplateColumn Header="Price" Width="60">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <TextBox Text="{Binding Price,StringFormat='c',UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
    
            <DataGridTemplateColumn Header="ServiceFee" Width="100">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <TextBox Text="{Binding ServiceFee,StringFormat='c',UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
    
            <DataGridTemplateColumn Header="Add"  Width="*" IsReadOnly="True">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <Button>Add</Button>
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
    
            <DataGridTemplateColumn Header="Remove" Width="*" IsReadOnly="True">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <Button>Remove</Button>
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
          </DataGrid.Columns>
        </DataGrid>
        <Button Grid.Row="1" Content="Load" Width="100" Margin="10" HorizontalAlignment="left"
                Command="{Binding Cmd}" CommandParameter="Load"/>
        <Button Grid.Row="1" Content="Clear" Width="100" Margin="10" HorizontalAlignment="Center"
                Command="{Binding Cmd}" CommandParameter="Clear"/>
        <Button Grid.Row="1" Content="Save" Width="100" Margin="10" HorizontalAlignment="Right"
                Command="{Binding Cmd}" CommandParameter="Save"/>
      </Grid>
    </Window>
    
    

    And classes:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Xml;
    using System.Xml.Linq;
    
    namespace WpfApp041
    {
    	class ProductPriceViewModel : INotifyPropertyChanged
    	{
    
    		// ctor
    		public ProductPriceViewModel() => ProductPriceList = new ObservableCollection<Products>();
    
    		// Path of xml file
    		public string FilePath { get; set; } = @"Window040XML.txt";
    
    		// View member
    		private CollectionViewSource cvs = new CollectionViewSource();
    		public ICollectionView View { get => cvs.View; }
    
    		private ObservableCollection<Products> _productPriceList;
    		private ObservableCollection<Products> ProductPriceList
    		{
    			get => this._productPriceList;
    			set
    			{
    				this._productPriceList = value;
    				cvs.Source = value;
    				OnPropertyChanged(nameof(View));
    			}
    		}
    
    		// Commands
    		public ICommand Cmd { get => new RelayCommand(executemethod, canexecutemethod); }
    
    		private void executemethod(object obj)
    		{
    			switch (obj.ToString())
    			{
    				case "Save":
    					SaveProductsPriceList();
    					break;
    				case "Clear":
    					ProductPriceList.Clear();
    					break;
    				case "Load":
    					ProductPriceList = GetProductsPriceList();
    					break;
    				default:
    					break;
    			}
    		}
    		private static bool canexecutemethod(object obj) => true;
    
    		private XmlDocument productDoc;
    
    #pragma warning disable CS8601 // Dereference of a possibly null reference.
    #pragma warning disable CS8602 // Dereference of a possibly null reference.
    		private ObservableCollection<Products> GetProductsPriceList() //to read xml file contents 
    		{
    			var products = new ObservableCollection<Products>();
    			productDoc = new XmlDocument();
    			productDoc.Load(FilePath);
    			XElement xe0 = XElement.Parse(productDoc.InnerXml);
    			foreach (var xe1 in xe0.Descendants("Products").Elements())
    			{
    				var p = new Products
    				{
    					SysId = xe1.Attribute("Sys_Oid")?.Value,
    					Mainproduct = xe1.Name.ToString(),
    					Name = xe1.Attribute("Name")?.Value,
    					Visible = xe1.Descendants("ProductVisibility")?.FirstOrDefault().Attribute("Visible")?.Value,
    					Price = xe1.Descendants("ProductPrice")?.FirstOrDefault().Attribute("Price")?.Value,
    					From = xe1.Descendants("ProductPrice")?.FirstOrDefault().Attribute("FromQuantity")?.Value,
    					ServiceFee = xe1.Descendants("ProductPrice").FirstOrDefault().Attribute("ServiceFee").Value,
    					NameIcon = xe1.Attribute("DefaultIconName")?.Value
    				};
    				products.Add(p);
    			}
    			return products;
    		}
    
    		private void SaveProductsPriceList() //to save xml fiel contents 
    		{
    			foreach (XmlElement pn in productDoc.SelectNodes("/Data/Products/*"))
    			{
    				Products pp = ProductPriceList.Where(p => p.SysId == pn.GetAttribute("Sys_Oid")?.ToString()).FirstOrDefault();
    				if (pp != null)
    				{
    					foreach (XmlNode visibility in pn.SelectNodes("Visibilities"))
    					{
    						foreach (XmlNode productVisibilty in visibility.SelectNodes("ProductVisibility"))
    						{
    							productVisibilty.Attributes["Visible"].InnerText = pp.Visible;
    
    							foreach (XmlNode price in productVisibilty.SelectNodes("Prices"))
    							{
    								foreach (XmlNode productPrice in price.SelectNodes("ProductPrice"))
    								{
    									productPrice.Attributes["FromQuantity"].InnerText = pp.From;
    									productPrice.Attributes["Price"].InnerText = pp.Price;
    									productPrice.Attributes["ServiceFee"].InnerText = pp.ServiceFee;
    								}
    							}
    
    						}
    
    					}
    				}
    			}
    			productDoc.Save(FilePath);
    		}
    
    		public static string RenameToCentiMeters(string inches)
    		{
    			var dic = GetInchesToCentimetersPairs();
    			foreach (var pair in dic.OrderByDescending(x => x.Key.Length))
    				inches = inches.Replace(pair.Key, pair.Value);
    			return inches;
    		}
    
    		private static Dictionary<string, string> GetInchesToCentimetersPairs()
    		{
    			var dic = new Dictionary<string, string>();
    			dic.Add("2x4", "5x10");
    			dic.Add("2x4/8", "5x10/20");
    			return dic;
    		}
    
    		// INotifyPropertyChanged
    #pragma warning disable CS8612 // Nullability of reference types in type doesn't match implicitly implemented member.
    		public event PropertyChangedEventHandler PropertyChanged;
    		public void OnPropertyChanged(String info) =>
    				PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
    	}
    
    	//#pragma warning disable CS8603 // Dereference of a possibly null reference.
    	public class Products
    	{
    		public string SysId { get; set; }
    		public string Mainproduct { get; set; }
    		public string Name { get; set; }
    		public string Visible { get; set; }
    		public string From { get; set; }
    		public string FromQuantity { get; set; }
    		public string Price { get; set; }
    		public string ServiceFee { get; set; }
    		//public List<string> FromQuantity { get; set; }= new List<string>();
    		//public List<string> Price { get; set; } = new List<string>();
    		//public List<string> ServiceFee { get; set; } = new List<string>();
    		public string NameIcon { get; set; }
    	}
    
    #pragma warning disable CS8767 // Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes).
    #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
    	public class RelayCommand : ICommand
    	{
    		private readonly Predicate<object> _canExecute;
    		private readonly Action<object> _action;
    		public RelayCommand(Action<object> action) { _action = action; _canExecute = null; }
    		public RelayCommand(Action<object> action, Predicate<object> canExecute) { _action = action; _canExecute = canExecute; }
    		public void Execute(object o) => _action(o);
    		public bool CanExecute(object o) => _canExecute == null ? true : _canExecute(o);
    		public event EventHandler CanExecuteChanged
    		{
    			add { CommandManager.RequerySuggested += value; }
    			remove { CommandManager.RequerySuggested -= value; }
    		}
    	}
    }
    

    Result:

    x