简体   繁体   中英

Best way to serialize and deserialize XML in C# so as to reuse the XML file, model class, and UserControl

I have an XML File that contains data that will ultimately be shown in two UserControls. Most of the data is common, and some is particular to the UserControl in question. I want to be a good citizen and reuse code as much as possible. To give a specific example (greatly simplified), consider this XML:

<?xml version="1.0"?>
<Model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<Widgets>
<Widget>
  <Name>Fork</Name>
  <VisibleAtHome>true</VisibleAtHome>
  <VisibleAtRestaurant>true</VisibleAtRestaurant>
</Widget>
<Widget>
  <Name>ProfessionalMixer</Name>
  <VisibleAtHome>false</VisibleAtHome>
  <VisibleAtRestaurant>true</VisibleAtRestaurant>
</Widget>
</Widgets>
</Model>

Ultimately, I want to show this info on two UserControls, one for the Home Kitchen, and one for a Restaurant. On those two controls, I'd like to just show

Name: Visible:

Obviously, on the Home Kitchen control, I'd like to show "VisibleAtHome", and on the Restaurant, "VisibleAtRestaurant". Possibly, the way I'm doing things is the best that can be done. But note that I have to have two controls that are almost identical. On one control, I need to bind to VisibleAtHome and on the other VisibleAtRestaurant. It would be nice to just have one control.

I can think of some possible improvements.

  1. Perhaps it's possible to use just 1 control and change the bindings at runtime. This has merit, but I think it might be hard to do given that the properties in question are inside of collections that might in turn be in collections (remember, I'm presenting a much simplified example).

  2. Perhaps in my model class I could have just the property "Visible" and read in VisibleAtHome or VisibleAtRestaurant depending on what I need. See Can I add attributes to an object property at runtime? for how this might be done, but note that the way I'm currently doing things, I read in the whole file into a model, and then save the whole model back to file. I don't want to lose info on VisibleAtRestaurant just because I'm working on VisibleAtHome.

  3. I could have a non-serializable property "Visible", that returns VisibleAtHome or VisibleAtRestaurant depending on what is passed into a constructor. Not sure this will work though as you need parameterless constructors when you're serializing/deserializing (correct?). Also, Model class would have to somehow tell Widget class about what's going on.

Anyone have any ideas on this? Again, my goal would be to just have (a) one XML file (actually, that's a must!), (b) one model class, and (c) one UserControl. (d) I'd prefer not to have to type VisibleAtRestaurant and VisibleAtHome everywhere. That's a maintenance nightmare. I have done a) and b). Now I just need help on c) and d). This question came about because I started with a Model that just needed to be display in 1 user control, and (you guessed it), someone (boss) decided we needed to show the model in a different situation where most of the properties are the same but some properties might have different values depending on where you are showing the model. My "Kitchen" versus "Restaurant" idea was my attempt to both simplify and hide proprietary info.

Thanks Dave

PS, Here are my model classes:

 public class Model :  INotifyPropertyChanged
{
    public Model()
    {

    }
    private List<Widget> _widgets = new List<Widget>();

    [System.Xml.Serialization.XmlArray("Widgets"),
    System.Xml.Serialization.XmlArrayItem(typeof(Widget))]
    public Widget[] Widgets
    {
        get { return _widgets.ToArray(); }
        set
        {
            _widgets = new List<Widget>(value);//value;
            OnPropertyChanged("Widgets");
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    /// <summary>
    /// Raises this object's PropertyChanged event.
    /// </summary>
    /// <param name="propertyName">The property that has a new value.</param>
    protected virtual void OnPropertyChanged(string propertyName)
    {

        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }
}


public class Widget :  INotifyPropertyChanged
{
    private string _name;
    public string Name
    {
        get {
            return _name;
        }
        set 
        {
            if (_name != value)
            {
                _name = value;
                OnPropertyChanged("Name");
            }
        }
    }

    // many more common properties in real case...

    private string _visibleAtHome;
    public string VisibleAtHome
    {
        get {
            return _visibleAtHome;
        }
        set 
        {
            if (_visibleAtHome != value)
            {
                _visibleAtHome = value;
                OnPropertyChanged("VisibleAtHome");
            }
        }
    }

    private string _visibleAtRestaurant;
    public string VisibleAtRestaurant
    {
        get {
            return _visibleAtRestaurant;
        }
        set 
        {
            if (_visibleAtRestaurant != value)
            {
                _visibleAtRestaurant = value;
                OnPropertyChanged("VisibleAtRestaurant");
            }
        }
    }

     public event PropertyChangedEventHandler PropertyChanged;
    /// <summary>
    /// Raises this object's PropertyChanged event.
    /// </summary>
    /// <param name="propertyName">The property that has a new value.</param>
    protected virtual void OnPropertyChanged(string propertyName)
    {

        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }
}

Use a model class for home and another model class for restaurant and get rid of this elements VisibleAt. Suppose you should add another entity like a food expo, you just create another model class for it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM