0

I have tried to read/save xml file to datagrid and I'm using dataset to do it. Now I have succeed to load xml file data to datagrid, the code as follows:

public class StoreDbDataSet
{
    internal static DataSet ReadDataSet()
    {
        DataSet ds = new DataSet();
        ds.ReadXmlSchema("store.xsd");
        ds.ReadXml("store.xml");
        return ds;
    }

}

And:

public class StoreDb
{
    public ObservableCollection<Product> GetProducts()
    {
        DataSet ds = StoreDbDataSet.ReadDataSet();

        ObservableCollection<Product> products = new ObservableCollection<Product>();
        foreach (DataRow productRow in ds.Tables["Products"].Rows)
        {
            products.Add(new Product((string)productRow["ModelNumber"],
                (string)productRow["ModelName"], (string)productRow["InputAddress"],
                (string)productRow["OutputAddress"], (string)productRow["DiagAddress"],
                (string)productRow["Description"], (byte)productRow["CategoryID"],
                (string)productRow["CategoryName"], (string)productRow["ProductImage"]));
        }
        return products;
    }
}

Xaml File:

<DataGrid Name="dgBasicInfo" ItemsSource="{Binding ProductsView, Mode=TwoWay}" CanUserResizeColumns="False" AutoGenerateColumns="False" Margin="10,10,10,15" BorderThickness="5" FontSize="14" Background="White">
   <DataGrid.Columns>
       <DataGridTextColumn Header="SlaveId" Binding="{Binding CategoryID}" />
       <DataGridTextColumn Header="ModelName" Binding="{Binding ModelName}"/>
       <DataGridTextColumn Header="CategoryName" Binding="{Binding CategoryName}" />
       <DataGridTextColumn Header="InputAddress" Binding="{Binding InputAddress}" />
       <DataGridTextColumn Header="OutputAddress" Binding="{Binding OutputAddress}" />
       <DataGridTextColumn Header="DiagAddress" Binding="{Binding DiagAddress}" />
       <DataGridTextColumn Header="Specification" Binding="{Binding Description}" />
    </DataGrid.Columns>
</DataGrid>

The ViewModel:

    public ICollectionView ProductsView
    {
        get { return _ProductsView; }
        set
        {
            _ProductsView = value;
            NotifyPropertyChanged();
        }
    }

My question is when I changed the datagrid data, how can I save the changes to xml?Thanks in advance!

---------------------------update-------------------------------

    private void RefreshProductList()
    {
        ProductsView = new ListCollectionView(sdb.GetProducts())
        {
            Filter = obj =>
            {
                var Product = (Product)obj;
                return SelectedProduct != null && Product.ModelNumber == SelectedProduct.ModelNumber;
            }
        };
    }

    private Product selectedProduct;
    public Product SelectedProduct
    {

        get { return selectedProduct; }
        set
        {
            if (selectedProduct != value)
            {
                selectedProduct = value;
                NotifyPropertyChanged();
                RefreshProductList();
                RefreshModule();
                RefreshCommunication();
                List<Product> productlist = ProductsView.ToList();
                File.WriteAllText("store.xml", productlist.ToXML());
            }
        }
    }
Lee Barry
  • 37
  • 9
  • How about [WriteXml](https://msdn.microsoft.com/en-us/library/system.data.dataset.writexml(v=vs.110).aspx)? – CodingYoshi Jun 13 '17 at 03:11
  • I did that, but it just creat a new empty xml file. – Lee Barry Jun 13 '17 at 03:14
  • which component that you writes to xml? you are binding your data to ProductsView, see the changes on the setter method there. if it is changed, then writes it to XML. – Grand Julivan Jun 13 '17 at 03:15
  • Sorry, I have updated the correct code. – Lee Barry Jun 13 '17 at 03:19
  • It seems that when I changed the data in the datagrid, System didn't call NotifyPropertyChanged in the ProductView method – Lee Barry Jun 13 '17 at 03:21
  • @Grand Julivan I add a button click event to save changes to xml, as i mentioned it just creat a new empty xml file at the destination path. – Lee Barry Jun 13 '17 at 03:35
  • you need to make sure your class implements the BindableBase , or Screen, or anything that could notify the propertychanged, and the ProductsView as well, have to implement the notify property changed. you could start by also posting your "ProductsView" class here – Grand Julivan Jun 13 '17 at 03:44
  • @Grand Julivan The ProductsView did notify property changed, but just write a new xml file instead of update the data inside – Lee Barry Jun 13 '17 at 07:48
  • Put changes back into the DataSet. The rows and columns indexes of the DGV are the same as the DataTables in the DataSet. – jdweng Jun 13 '17 at 08:21
  • @jdweng I use `WriteXml` method but just create a new xml file, why did this happen? – Lee Barry Jun 14 '17 at 09:09
  • Don't understand question. – jdweng Jun 14 '17 at 11:20

1 Answers1

1

The problem is you are reading xml as a dataset instead read it as product and save it as array of product as below

Your xml format should look like this

<ArrayOfProduct>
<Product>
<ModelNumber>abc</ModelNumber>
//remaking properties 
</Product>
</ArrayOfProduct>

Create an extension method class, this help you convert xml to list vice versa

public static class ExtensionMethods
{
    /// <summary>
    /// Converts given class to XML using xml serialization
    /// </summary>
    /// <typeparam name="T">Type of Class</typeparam>
    /// <param name="classObject">Class to be serialized</param>
    /// <returns>Xml string</returns>
    public static string ToXML<T>(this T classObject) where T : class
    {
        XmlSerializer xmls = new XmlSerializer(typeof(T));
        using (MemoryStream ms = new MemoryStream())
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = new UTF8Encoding(false);
            settings.Indent = true;
            settings.IndentChars = "\t";
            settings.NewLineChars = Environment.NewLine;
            settings.OmitXmlDeclaration = true;
            settings.ConformanceLevel = ConformanceLevel.Document;
            using (XmlWriter writer = XmlTextWriter.Create(ms, settings))
            {
                xmls.Serialize(writer, classObject);
            }

            string xml = Encoding.UTF8.GetString(ms.ToArray());
            return xml;
        }
    }

    /// <summary>
    /// Converts given XML string to class of type T
    /// </summary>
    /// <typeparam name="T">Type to be converted</typeparam>
    /// <param name="XmlData">xml string</param>
    /// <returns>class of Type T</returns>
    public static T ToClass<T>(this string XmlData)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        T newClass;
        using (XmlTextReader reader = new XmlTextReader(new StringReader(XmlData)))
        {
            //reader.Namespaces = false;
            newClass = (T)serializer.Deserialize(reader);
        }
        return newClass;
    }
}

Now your store db should look like this

public class StoreDb
{
    public ObservableCollection<Product> GetProducts()
    {
        string StoreData = string.Empty;
        using(StreamReader sr = new StreamReader("store.xml"))
          {
              StoreData = sr.ReadToEnd();
          }
        ObservableCollection<Product> products = new ObservableCollection<Product>(StoreData.ToClass<List<Product>());

        return products;
    }
}

Change productsView to observablecollection

private ObservableCollection<Product> _ProductsView;
public ObservableCollection<Product> ProductsView
    {
        get { return _ProductsView; }
        set
        {
            _ProductsView = value;
            NotifyPropertyChanged();
        }
    }

Now after your changes save xml as below

File.WriteAllText("store.xml",ProductsView.ToList().ToXml());
Krishna
  • 1,945
  • 1
  • 13
  • 24