序列化自定义分层集合中的问题

时间:2011-06-12 06:28:03

标签: observablecollection hierarchical-data xmlserializer

我必须填充一个树形视图,我已经为其制作了一个自定义集合 以下是自定义集合的类

public class EntityBase : ObservableCollection<object>
{
    private string name;

    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            InvokePropertyChange(this, new PropertyChangedEventArgs("Name"));
        }
    }        

    public event PropertyChangedEventHandler PropertyChanged;

    public void InvokePropertyChange(object sender, PropertyChangedEventArgs e)             
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(sender, e);
        }
    }


}

public class ParentX : EntityBase // Should be the root of my XML
{

}

public class Parent : EntityBase
{
    private ChildC _childC;        

    public ChildC ChildC
    {
        get { return _childC; }
        set { _childC = value; }
    }
}

public class ChildA : EntityBase
{

}

public class ChildB : EntityBase
{

}

public class ChildC : EntityBase
{
    private ObservableCollection<ChildB> children = new ObservableCollection<ChildB>();

    public ObservableCollection<ChildB> Children
    {
        get { return children; }
        set { children = value; }
    }
}

以下是我如何按层次顺序填充数据,以便填充异质树...

public class DataBase
{
    public ObservableCollection<object> GetData()
    {

        ChildB childB1 = new ChildB { Name = "Parent 1 - ChildB 1" };
        ChildB childB2 = new ChildB { Name = "Parent 1 - ChildB 2" };
        ChildA childA1 = new ChildA { childB1, childB2 }; // ChildA will have ChildB objects as its child
        childA1.Name = "Parent 1 - ChildA 1";

        ChildC childC = new ChildC{Name="CHildC"};
        for (int i = 0; i < 5; i++)
        {
            childC.Children.Add(new ChildB{Name="Pappu" + i}); // childC children Property will have childB Object
        }
        Parent parent1 = new Parent {childC, childA1}; // Parent class will have ChildC and ChildA as its child
        parent1.Name = "Parent1";

        //Family 2
        ParentX parentX=new ParentX{Name="Parent"};
        parentX.Add(parent1);                           //ParentX will have Parent as its child

        return new ObservableCollection<object> { parentX };
    }
}  

这是我正在使用的序列化代码.....

using (FileStream fileStream=new FileStream(@"D:\text.xml",FileMode.Create))
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(ParentX), new Type[] { typeof(Parent), typeof(ChildA), typeof(ChildC), typeof(ChildB)});
            if (data != null) xmlSerializer.Serialize(fileStream, data);
        }  

我被困在这.....它没有序列化它给出错误....

{"There was an error generating the XML document."}  
"The type HierarchialTreeView.Model.ChildC may not be used in this context."  

Plz帮助我被困在这个真正的坏人身上 很难填充所需类型的Heterogenious树视图,现在发生这种情况

谢谢Ne方式......社区非常有帮助:)

编辑:
内部例外:
    {“HierarchialTreeView.Model.ChildC类型可能不会在此上下文中使用。”}
    内在异常= null
在此之后没有更多的例外....(内在内在的前)

堆栈跟踪(如果有人需要):

System.InvalidOperationException was unhandled
Message=There was an error generating the XML document.
Source=System.Xml
StackTrace:
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   at System.Xml.Serialization.XmlSerializer.Serialize(Stream stream, Object o, XmlSerializerNamespaces namespaces)
   at System.Xml.Serialization.XmlSerializer.Serialize(Stream stream, Object o)
   at HierarchialTreeView.MainWindow.Button_Click(Object sender, RoutedEventArgs e)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
   at System.Windows.Controls.Primitives.ButtonBase.OnClick()
   at System.Windows.Controls.Button.OnClick()
   at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
   at System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e)
   at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
   at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
   at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
   at System.Windows.Input.InputManager.ProcessStagingArea()
   at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
   at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
   at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
   at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.Run()
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at System.Windows.Application.Run(Window window)
   at System.Windows.Application.Run()
   at HierarchialTreeView.App.Main()
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()
InnerException: System.InvalidOperationException
   Message=The type HierarchialTreeView.Model.ChildC may not be used in this context.
   Source=System.Xml
   StackTrace:
        at System.Xml.Serialization.XmlSerializationWriter.WriteTypedPrimitive(String name, String ns, Object o, Boolean xsiType)
        at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterParentX.Write1_Object(String n, String ns, Object o, Boolean isNullable, Boolean needType)
        at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterParentX.Write1_Object(String n, String ns, Object o, Boolean isNullable, Boolean needType)
        at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterParentX.Write2_ArrayOfAnyType(Object o)
   InnerException: 

1 个答案:

答案 0 :(得分:0)

以下是可以序列化的父/子节点层次结构的示例。请注意使用公共类Entity,它既用于ObservableCollections又用作Node的基类。实体上使用 XmlInclude属性来提醒序列化程序如何处理作为节点的实体。

另请注意,此example在另一个层次结构中显示XmlInclude用法。

控制台输出和序列化XML包含在下面。

using System;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Collections.Specialized;
using System.IO;
using System.Xml.Serialization;


namespace StackoverflowSerializingHierarchy
{

    // Use System.Xml.Serialization.XmlInclude attribute to let 
    // serialize know how to handle an Entity that is a Node
    [XmlInclude(typeof(Node))]
    public abstract class Entity : INotifyPropertyChanged
    {
        // INotifyPropertyChanged implementation
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }


        // Name Property
        private string _name;
        public string Name
        {
            get {
                return _name;
            }

            set {
                if (value == null) 
                        value = String.Empty;

                if (String.IsNullOrEmpty(_name) || !_name.Equals(value)) {
                       _name = value;
                        OnPropertyChanged("Name");
                }
            }    
        }
    }


    // use a Node class to represent an Entity that can have children
    public class Node : Entity
    {
        public Node() : base()
        {
            PropertyChanged += DataBase.DataPropertyChanged;
        }

        // Children property is an observable collection of the common base class Entity
        private ObservableCollection<Entity> _children;
        public ObservableCollection<Entity> Children
        {
            get
            {
                return this._children;
            }

            set
            {
                this._children = value;
                if (this._children != null)
                {
                    this._children.CollectionChanged += DataBase.DataCollectionChanged;
                }
            }
        }
    }


    class Util
    {
        public static void SerializeObjectToXML<T>(T item, string FilePath)
        {
            XmlSerializer xs = new XmlSerializer(typeof(T));
            using (StreamWriter wr = new StreamWriter(FilePath))
            {
                xs.Serialize(wr, item);
            }
        }
    }

    public class DataBase
    {
        public static void DataCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            string name = "N/A";
            if (sender is Entity) // will be called for EntityBase and ObservableCollection<ChildB> via ChildC
            {
                name = ((Entity)sender).Name;
            }            
            Console.WriteLine("Collection changed: performed {0} on ({1}) of type {2}", e.Action, name, sender.GetType().Name);

        }

        public static void DataPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (sender is Entity && e.PropertyName == "Name")
            {
                string name = ((Entity)sender).Name;
                Console.WriteLine("Data Property Changed {0} to ({1}) on type {2}", e.PropertyName, name, sender.GetType().Name);
            }
        }


        public Node GetData()
        {
            Node childB1 = new Node { Name = "Parent 1 - ChildB 1" };

            Node childB2 = new Node { Name = "Parent 1 - ChildB 2" };

            Node childA1 = new Node { Name = "Parent 1 - ChildA 1", 
                Children  = new ObservableCollection<Entity>{childB1, childB2 }};

            // ChildA will have ChildB objects as its child

            Node childC = new Node { Name = "ChildC", Children = new ObservableCollection<Entity>()};

            for (int i = 0; i < 5; i++)
            {
                //childC.
                childC.Children.Add(new Node { Name = "Pappu" + i }); // childC children Property will have childB Object
            }


            Node parent1 = new Node { Name = "Parent 1", 
                Children = new ObservableCollection<Entity>{ childC, childA1 }};


            //Family 2
            Node parentX = new Node { Name = "Parent", Children = new ObservableCollection<Entity> { parent1} };

            return parentX;
        }

    }  


    class Program
    {
        static void Main(string[] args)
        {
            DataBase db = new DataBase();
            Node data = db.GetData();
            Util.SerializeObjectToXML<Node>(data, @"d:\tmp\test.txt");
        }
    }
}

控制台输出:

Data Property Changed Name to (Parent 1 - ChildB 1) on type Node
Data Property Changed Name to (Parent 1 - ChildB 2) on type Node
Data Property Changed Name to (Parent 1 - ChildA 1) on type Node
Data Property Changed Name to (ChildC) on type Node
Data Property Changed Name to (Pappu0) on type Node
Collection changed: performed Add on (N/A) of type ObservableCollection`1
Data Property Changed Name to (Pappu1) on type Node
Collection changed: performed Add on (N/A) of type ObservableCollection`1
Data Property Changed Name to (Pappu2) on type Node
Collection changed: performed Add on (N/A) of type ObservableCollection`1
Data Property Changed Name to (Pappu3) on type Node
Collection changed: performed Add on (N/A) of type ObservableCollection`1
Data Property Changed Name to (Pappu4) on type Node
Collection changed: performed Add on (N/A) of type ObservableCollection`1
Data Property Changed Name to (Parent 1) on type Node
Data Property Changed Name to (Parent) on type Node
Press any key to continue . . .

序列化XML输出文件:

<?xml version="1.0" encoding="utf-8"?>
<Node xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Parent</Name>
  <Children>
    <Entity xsi:type="Node">
      <Name>Parent 1</Name>
      <Children>
        <Entity xsi:type="Node">
          <Name>ChildC</Name>
          <Children>
            <Entity xsi:type="Node">
              <Name>Pappu0</Name>
            </Entity>
            <Entity xsi:type="Node">
              <Name>Pappu1</Name>
            </Entity>
            <Entity xsi:type="Node">
              <Name>Pappu2</Name>
            </Entity>
            <Entity xsi:type="Node">
              <Name>Pappu3</Name>
            </Entity>
            <Entity xsi:type="Node">
              <Name>Pappu4</Name>
            </Entity>
          </Children>
        </Entity>
        <Entity xsi:type="Node">
          <Name>Parent 1 - ChildA 1</Name>
          <Children>
            <Entity xsi:type="Node">
              <Name>Parent 1 - ChildB 1</Name>
            </Entity>
            <Entity xsi:type="Node">
              <Name>Parent 1 - ChildB 2</Name>
            </Entity>
          </Children>
        </Entity>
      </Children>
    </Entity>
  </Children>
</Node>