我正在努力实现这一目标:将 Silverlight 应用程序的状态保存到 isolateduserstorage
,以便在下次启动时重新加载它。我需要存储一个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
};
}
}
}
UIElement
不支持序列化,则必须将其序列化为字符串的XML,将其保存到独立存储或DB,将其从XML反序列化回视图模型。
您是否尝试过使用 Xaml 序列化服务?如果要取消/序列化 xaml 内容,最好使用这些内容,而不是常规的 xml 序列化。这篇博文描述了这一切。