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: