0

我正在努力实现这个目标:将 Silverlight 应用程序的状态保存到isolateduserstorage,以便在下次启动时重新加载它。我需要存储 a List ObservableCollection<UIElement>UIElements它们是由工厂创建的(实际上我正在Shapes那里创建)。

问题是,这Serialization会引发异常(您将在下面找到)。我知道问题可能是什么(Serialization不知道如何存储UIElements(?)),但是,我不知道如何解决这个问题。

例外:

System.InvalidOperationException was unhandled by user code
  Message=There was an error generating the XML document.
  StackTrace:
       bei System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
       bei System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle)
       bei System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces)
       bei System.Xml.Serialization.XmlSerializer.Serialize(Stream stream, Object o, XmlSerializerNamespaces namespaces)
       bei System.Xml.Serialization.XmlSerializer.Serialize(Stream stream, Object o)
       bei Dojo_2_wi10b012.ViewModel.ViewModel.StoreContent()
       bei Dojo_2_wi10b012.ViewModel.RelayCommand.Execute(Object parameter)
       bei System.Windows.Controls.Primitives.ButtonBase.ExecuteCommand()
       bei System.Windows.Controls.Primitives.ButtonBase.OnClick()
       bei System.Windows.Controls.Button.OnClick()
       bei System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
       bei System.Windows.Controls.Control.OnMouseLeftButtonUp(Control ctrl, EventArgs e)
       bei MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName, UInt32 flags)
  InnerException: System.InvalidOperationException
       Message=The type System.Windows.Shapes.Ellipse was not expected. Use the XmlInclude attribute to specify types that are not known statically.
       StackTrace:
            bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterObservableCollection1.Write12_UIElement(String n, String ns, UIElement o, Boolean isNullable, Boolean needType)
            bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterObservableCollection1.Write13_ArrayOfUIElement(Object o)
       InnerException: 

ViewModel:(重要部分是方法“StoreContent()”)

using System;
using System.Net;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Dojo_2_wi10b012.Model;
using System.ComponentModel;
using System.Reflection;
using System.IO.IsolatedStorage;
using System.IO;
using System.Xml.Serialization;

namespace Dojo_2_wi10b012.ViewModel
{
    public class ViewModel : INotifyPropertyChanged
    {
        private List<UIElement> _shapeList = new List<UIElement>();
        private ShapeFactory theFactory = new ShapeFactory();
        private ObservableCollection<UIElement> _elements = new ObservableCollection<UIElement>();
        private UIElement _selectedItem ;
        private UIElement _alteredSelectedItem;
        private ObservableCollection<KeyValuePair<string, Color>> _theColors = new ObservableCollection<KeyValuePair<string, Color>>();
        private KeyValuePair<string, Color> _selectedBrush = new KeyValuePair<string, Color>();
        private KeyValuePair<string, Color> _selectedStroke = new KeyValuePair<string, Color>();
        private SolidColorBrush _selectedBrushBrush = new SolidColorBrush();
        private SolidColorBrush _selectedStrokeBrush = new SolidColorBrush();
        private int _heightText;
        private int _widthText;
        private string filename = "uielements"; //for isolatedstorage         

        #region EventHandler
        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

        public ViewModel()
        {
            GetShapesCommand = new RelayCommand(GetShapes);
            GetShapesCommand.IsEnabled = true;
            LoadColors();
            ChangeShapeCommand = new RelayCommand(ChangeShape);
            ChangeShapeCommand.IsEnabled = true;
            StoreContentCommand = new RelayCommand(StoreContent);
            StoreContentCommand.IsEnabled = true;
        }

        #region properties

        public int HeightText
        {
            get { return _heightText; }
            set
            {
                _heightText = value;
                NotifyPropertyChanged("HeightText");
            }
        }

        public int WidthText
        {
            get { return _widthText; }
            set
            {
                _widthText = value;
                NotifyPropertyChanged("WidthText");
            }
        }

        public SolidColorBrush SelectedBrushBrush
        {
            get { return _selectedBrushBrush; }
            set
            {
                _selectedBrushBrush = value;
                NotifyPropertyChanged("SelectedBrushBrush");
            }
        }

        public SolidColorBrush SelectedStrokeBrush
        {
            get { return _selectedStrokeBrush; }
            set
            {
                _selectedStrokeBrush = value;
                NotifyPropertyChanged("SelectedStrokeBrush");
            }
        }

        public KeyValuePair<string, Color> SelectedBrush
        {
            get { return _selectedBrush; }
            set
            {
                _selectedBrush = value;
                NotifyPropertyChanged("SelectedBrush");
                SelectedBrushBrush = new SolidColorBrush(value.Value);
            }
        }

        public KeyValuePair<string, Color> SelectedStroke
        {
            get { return _selectedStroke; }
            set
            {
                _selectedStroke = value;
                NotifyPropertyChanged("SelectedStroke");
                SelectedStrokeBrush = new SolidColorBrush(value.Value);
            }
        }

        public ObservableCollection<KeyValuePair<string, Color>> TheColors
        {
            get { return _theColors; }
            set 
            { 
                _theColors = value;
                NotifyPropertyChanged("TheColors");
            }
        }

        public List<UIElement> ShapeList
        {
            get { return _shapeList; }
            set
            {
                _shapeList = value;
                NotifyPropertyChanged("ShapeList");
            }
        }

        public ObservableCollection<UIElement> Elements
        {
            get { return _elements; }
            set 
            { 
                _elements = value;
                NotifyPropertyChanged("Elements");
            }
        }

        public UIElement SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                _selectedItem = value;
                NotifyPropertyChanged("SelectedItem");
            }
        }

        public UIElement AlteredSelectedItem
        {
            get { return _alteredSelectedItem; }
            set
            {
                _alteredSelectedItem = value;
                NotifyPropertyChanged("AlteredSelectedItem");
            }
        }

        public RelayCommand GetShapesCommand { get; private set; }
        public RelayCommand ChangeShapeCommand { get; private set; }
        public RelayCommand StoreContentCommand { get; private set; }


        #endregion

        #region PrivateMethods
        private void GetShapes()
        {
            UIElement temp = theFactory.ProduceShape();
            temp.MouseLeftButtonDown += Handle_MouseDown;
            temp.MouseMove += Handle_MouseMove;
            temp.MouseLeftButtonUp += Handle_MouseUp;
            temp.MouseRightButtonDown += Handle_RightMouseDown;
            ShapeList.Add(temp); //add the new shape to the list where we store the shapes
            Elements.Add(temp);
        }

        private void ChangeShape()
        {
            AlteredSelectedItem = SelectedItem;
            Shape temp = FigureOutShape(AlteredSelectedItem);
            double debugheight = temp.Height;
            double debugwidth = temp.Width;
            temp.Height = HeightText;
            temp.Width = WidthText;
            temp.Fill = SelectedBrushBrush;
            temp.Stroke = SelectedStrokeBrush;
            SelectedItem = (UIElement)temp;
        }

        private Shape FigureOutShape(UIElement input)
        {
            if (input != null)
            {
                if (input is Ellipse)
                {
                    return (Ellipse)input;
                }
                else { return (Rectangle)input; }
            }
            else //default if the user hasn't selected a shape
                return new Ellipse()
                {
                    Width = 25,
                    Height = 25,
                    Stroke = new SolidColorBrush(Colors.Green),
                    Fill = new SolidColorBrush(Colors.DarkGray),
                    StrokeThickness = 2,
                    Visibility = Visibility.Visible,
                    Cursor= Cursors.Hand,
                    Margin = new Thickness(25, 30, 0, 0) //define initial position on canvas randomly
                };
        }

        private void StoreContent()
        {
            //Hint from Mr. Eckkrammer (wiki):
            using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
            {
                IsolatedStorageFileStream isoRegisterFileStream;

                isoRegisterFileStream = new IsolatedStorageFileStream(filename, FileMode.Create, isf);

                XmlSerializer serializer = new XmlSerializer(Elements.GetType());

                serializer.Serialize(isoRegisterFileStream, Elements);

                //close file stream
                isoRegisterFileStream.Close();
            }

        }

        private void LoadContent()
        {
            /*
            try
            {
            Elements as ObservableCollection<UIElement> = IsolatedStorageSettings.ApplicationSettings(filename);
            }
            catch
            {
            //no idea what to do here...
            }
            */
            using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (IsolatedStorageFileStream isfs = new IsolatedStorageFileStream(filename, FileMode.Open, isf))
                {
                    using (StreamReader sr = new StreamReader(isfs))
                    {

                        // string lineOfData = String.Empty;
                        // while ((lineOfData = sr.ReadLine()) != null)
                        // data += lineOfData;

                        //no idea what to do here...

                    }
                }
            }


        }



        //when the user right clicks a shape, the "selectedItem" will  be updated
        private void Handle_RightMouseDown(object sender, MouseEventArgs args)
        {
            UIElement item = sender as UIElement;
            SelectedItem = item;
        }

        private void LoadColors()
        {
            //unfortunately I have no idea how to do the following automatically, so I need to do it by hand :-(
            TheColors.Add(new KeyValuePair<string,Color>("Black",Colors.Black));
            TheColors.Add(new KeyValuePair<string,Color>("Blue",Colors.Blue));
            TheColors.Add(new KeyValuePair<string,Color>("Brown",Colors.Brown));
            TheColors.Add(new KeyValuePair<string,Color>("Cyan",Colors.Cyan));
            TheColors.Add(new KeyValuePair<string,Color>("DarkGray",Colors.DarkGray));
            TheColors.Add(new KeyValuePair<string,Color>("Gray",Colors.Gray));
            TheColors.Add(new KeyValuePair<string,Color>("Green",Colors.Green));
            TheColors.Add(new KeyValuePair<string, Color>("LightGray", Colors.LightGray));
            TheColors.Add(new KeyValuePair<string,Color>("Magenta",Colors.Magenta));
            TheColors.Add(new KeyValuePair<string,Color>("Orange",Colors.Orange));
            TheColors.Add(new KeyValuePair<string,Color>("Purple",Colors.Purple));
            TheColors.Add(new KeyValuePair<string,Color>("Red",Colors.Red));
            TheColors.Add(new KeyValuePair<string,Color>("White",Colors.White));
            TheColors.Add(new KeyValuePair<string,Color>("Yellow",Colors.Yellow));
        }
        #endregion

        #region DragAndDropImplementation

        private bool isMouseCaptured;
        private double mouseVerticalPosition;
        private double mouseHorizontalPosition;

        private void Handle_MouseDown(object sender, MouseEventArgs args)
        {
            UIElement item = sender as UIElement;
            mouseVerticalPosition = args.GetPosition(null).Y;
            mouseHorizontalPosition = args.GetPosition(null).X;
            isMouseCaptured = true;
            item.CaptureMouse();
        }

        private void Handle_MouseMove(object sender, MouseEventArgs args)
        {
            UIElement item = sender as UIElement;
            if (isMouseCaptured)
            {

                // Calculate the current position of the object.
                double deltaV = args.GetPosition(null).Y - mouseVerticalPosition;
                double deltaH = args.GetPosition(null).X - mouseHorizontalPosition;
                double newTop = deltaV + (double)item.GetValue(Canvas.TopProperty);
                double newLeft = deltaH + (double)item.GetValue(Canvas.LeftProperty);

                // Set new position of object.
                item.SetValue(Canvas.TopProperty, newTop);
                item.SetValue(Canvas.LeftProperty, newLeft);

                // Update position global variables.
                mouseVerticalPosition = args.GetPosition(null).Y;
                mouseHorizontalPosition = args.GetPosition(null).X;
            }
        }

        private void Handle_MouseUp(object sender, MouseEventArgs args)
        {
            UIElement item = sender as UIElement;
            isMouseCaptured = false;
            item.ReleaseMouseCapture();
            mouseVerticalPosition = -1;
            mouseHorizontalPosition = -1;
        }
        #endregion
    }
}

形状工厂.cs:

namespace Dojo_2_wi10b012.Model
{
    public class ShapeFactory
    {
        Random ran;
        Random xy;
        int thick = 5;
        public ShapeFactory()
        {
            ran = new Random();
            xy = new Random();
        }

        public Shape ProduceShape()
        {
            int guess = ran.Next(0, 4);
            int height = ran.Next(20, 80);
            int width = ran.Next(20, 80);
            int x = xy.Next(0,300);
            int y = xy.Next(25,300);

            if (guess == 0)//Ellipse
                return new Ellipse()
                {
                    Width = height,
                    Height = width,
                    Stroke = new SolidColorBrush(Colors.Green),
                    Fill = new SolidColorBrush(Colors.DarkGray),
                    StrokeThickness = thick,
                    Visibility = Visibility.Visible,
                    Cursor= Cursors.Hand,
                    Margin = new Thickness(x, y, 0, 0) //define initial position on canvas randomly
                };
            else if (guess == 1) //Rectangle
                return new Rectangle()
                {
                    Width = height,
                    Height = width,
                    Stroke = new SolidColorBrush(Colors.Brown),
                    Fill = new SolidColorBrush(Colors.LightGray),
                    StrokeThickness = thick,
                    Visibility = Visibility.Visible,
                    Cursor = Cursors.Hand,
                    Margin = new Thickness(x, y, 0, 0) //define initial position on canvas randomly
                };
            else if (guess == 2) //Square
                return new Ellipse()
                {
                    Width = height,
                    Height = height,
                    Stroke = new SolidColorBrush(Colors.Red),
                    StrokeThickness = thick,
                    Fill = new SolidColorBrush(Colors.Orange),
                    Visibility = Visibility.Visible,
                    Cursor = Cursors.Hand,
                    Margin = new Thickness(x, y, 0, 0) //define initial position on canvas randomly
                };
            else //Circle
                return new Rectangle()
                {
                    Width = height,
                    Height = height,
                    Stroke = new SolidColorBrush(Colors.Blue),
                    StrokeThickness = thick,
                    Fill = new SolidColorBrush(Colors.Cyan),
                    Visibility = Visibility.Visible,
                    Cursor = Cursors.Hand,                    
                    Margin = new Thickness(x, y, 0, 0) //define initial position on canvas randomly
                };
        }
    }
}
4

2 回答 2

1

UIElement不支持序列化,您必须将其序列化为 XML 作为字符串,将其保存到隔离存储或 DB,将其从 XML 反序列化回视图模型。

于 2012-06-03T19:22:02.670 回答
0

您是否尝试过使用 Xaml 序列化服务?如果您要对 xaml 内容进行反序列化/序列化,最好使用这些内容而不是常规的 xml 序列化。这篇博文描述了这一切。

于 2012-06-03T22:58:06.490 回答