Lee Barry Lee Barry -4 years ago 170
C# Question

WPF save dataset to xml

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
{
public DataTable GetProducts()
{
return ReadDataSet().Tables[0];
}

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());
}
}
}

Answer Source

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());
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download