[英]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.