[英]Serialization taking way too long
所以我正在开发一个UWP应用程序,我正在便携式类库(Xamarin)中创建。 我需要保存用户在xml文件中输入的信息(例如在TextBoxes中)。
因此我在PCL中创建了一个类,我从那些TextBox中获取信息:
namespace myProject
{
public class XMLData
{
[XmlRoot("MyRootElement")]
public class MyRootElement
{
[XmlAttribute("MyAttribute1")] //name of the xml element
public string MyAttribute1 //name of a textboxt e.g.
{
get;
set;
}
[XmlAttribute("MyAttribute2")]
public string MyAttribute2
{
get;
set;
}
[XmlElement("MyElement1")]
public string MyElement1
{
get;
set;
}
}
}
在每个页面上都有一个“继续”按钮。 单击时,数据将被保存:
async void Continue_Clicked(object sender, EventArgs e)
{
await Navigation.PushAsync(new Page2());
XMLData.MyRootElement mre = new XMLData.MyRootElement
{
MyAttribute1 = editor1.ToString(),
MyAttribute2 = editor2.ToString(),
MyElement1 = editor3.ToString()
};
}
在最后一个按钮单击应创建并保存的文件:
private void CreateandSave_Clicked(object sender, EventArgs e)
{
var s = DependencyService.Get<IFileHelper>().MakeFileStream();//using dependencyService to get a stream (there is no system.io.stream in PCL)
XMLData xmldat = new XMLData();
using (StreamWriter sw = new StreamWriter(s, Encoding.UTF8))
{
XmlSerializer serializer = new XmlSerializer(typeof(XMLData));
serializer.Serialize(sw, xmldat);
}
}
这里是我在UWP类中的代码(对于dependencyService,我创建了一个名为FileHelper的类来获取流并创建一个保存位置+文件)
namespace myProject.UWP
{
public class FileHelper: IFileHelper //IFileHelper is a simple interface I made with the Stream MakeFileStream(); method in it
{
public async Task<IRandomAccessStream> MakeFileStreamAsync()
{
StorageFolder sf = KnownFolders.DocumentsLibrary;
var file = await sf.CreateFileAsync("data.xml", CreationCollisionOption.OpenIfExists);
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
return stream;
}
}
Stream IFileHelper.MakeFileStream()
{
var task = MakeFileStreamAsync();
task.Wait();
return task.Result.AsStreamForWrite();
}
}
}
问题是每当我到达CreateandSave按钮并单击它时,应用程序就会冻结。 没有错误,没有,一切看起来都很好。 在我打破调试后,我可以看到在我想要的文件夹中创建了一个xml文件,但它是空的(0字节)。 代码有什么问题? 有人有想法吗?
在这段代码中:
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
return stream;
}
您正在返回由using
块创建的实例。 它将在返回之前处理,因此,您将返回已处置的对象。
将其更改为仅return stream
。 您使用的StreamWriter
本身位于一个using
块中,因此在它处理期间它将处理底层流 :
所述
StreamWriter
对象调用Dispose()
的设置在Stream
对象时StreamWriter.Dispose
被调用。
您的冻结问题是Task.Wait()
指令阻止主UI线程,直到MakeFileStreamAsync()
方法完成执行。
您应该使此方法async
并返回Task<Stream>
类型,并使用await关键字调用MakeFileStreamAsync
方法:
async Task<Stream> IFileHelper.MakeFileStream()
{
var stream = await MakeFileStreamAsync();
return stream.AsStreamForWrite();
}
因此,您创建点击的代码应该类似于:
private void CreateandSave_Clicked(object sender, EventArgs e)
{
var s = DependencyService.Get<IFileHelper>().MakeFileStream();//using dependencyService to get a stream (there is no system.io.stream in PCL)
XMLData xmldat = new XMLData();
// Here you should await your `s` Task:
await s;
using (StreamWriter sw = new StreamWriter(s, Encoding.UTF8))
{
XmlSerializer serializer = new XmlSerializer(typeof(XMLData));
serializer.Serialize(sw, xmldat);
}
}
希望能帮助到你!
编辑:关于你的空xml文件问题,我认为这是因为你将数据保存在另一个页面,但不做任何事情。 这意味着您在加载Page2
时会丢失它们。 因此,他们不是在可用CreateandSave_Clicked
方法,但目前保存空XMLDATA对象。
更直观的方法是将数据传递给Page2
构造函数,并将此数据类型添加为Page2
的公共属性。 所以你的Continue_Clicked
方法看起来像:
async void Continue_Clicked(object sender, EventArgs e)
{
// Note you must REVERSE instructions here
// Create first your object (save the user data in it)
XMLData.MyRootElement mre = new XMLData.MyRootElement
{
MyAttribute1 = editor1.ToString(),
MyAttribute2 = editor2.ToString(),
MyElement1 = editor3.ToString()
};
// Pass it to Page2 through the constructor
await Navigation.PushAsync(new Page2(mre));
}
因此Page2
类/构造函数变为:
public class Page2 : SomeParentClass
{
...
// add your XMLData property
public XMLData.MyRootElement mre { get; set; }
...
// the constructor
public Page2(XMLData.MyRootElement data){
// Save the user data in xmldat property. So this data could be reused later.
this.mre = data;
}
}
然后,如果它是负责创建和保存XML文件本身的Page2
,则可以重用通过构造函数传递的对象。
private void CreateandSave_Clicked(object sender, EventArgs e)
{
var s = DependencyService.Get<IFileHelper>().MakeFileStream();//using dependencyService to get a stream (there is no system.io.stream in PCL)
// You want to remove that here as you created a public property of type XMLData.MyRootElement (called mre) holding user data instead
//XMLData xmldat = new XMLData();
// Here you should await your `s` Task:
await s;
using (StreamWriter sw = new StreamWriter(s, Encoding.UTF8))
{
// Change of serialized type here
XmlSerializer serializer = new XmlSerializer(typeof(XMLData.MyRootElement));
// Here, just seralize the property saved through constructor
serializer.Serialize(sw, mre);
}
}
请注意,如果它是Page3
或负责保存XML文件的任何Page
,只需将已保存的用户数据从一个页面传递到另一个页面,并在调用CreateandSave_Clicked
方法时保存一次。
另一点是,我不确定将MyRootElement
类嵌套到XMLData
。 您可以删除XMLData
嵌套类,只需将MyRootElement
类保留为“主”类。
您也可以使用静态字段来实现相同的功能,因此不使用构造函数。 但从我的观点来看,它不那么直观,而且不太干净。
请享用,
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.