简体   繁体   中英

C# serialization UIElementCollection

I have some code:

    public static UIElementCollection DeSerializeXAML(string filename)
    {
        // Load XAML from file. Use 'using' so objects are disposed of properly.
        using (System.IO.FileStream fs = System.IO.File.Open(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read))
        {
            return System.Windows.Markup.XamlReader.Load(fs) as UIElementCollection; //EXCEPTION
        }
    }

    // Serializes any UIElement object to XAML using a given filename.
    public static void SerializeToXAML(UIElementCollection elements, string filename)
    {
        // Use XamlWriter object to serialize element
        string strXAML = System.Windows.Markup.XamlWriter.Save(elements);

        // Write XAML to file. Use 'using' so objects are disposed of properly.
        using (System.IO.FileStream fs = System.IO.File.Create(filename))
        {
            using (System.IO.StreamWriter streamwriter = new System.IO.StreamWriter(fs))
            {
                streamwriter.Write(strXAML);
            }
        }
    }

    private void btnSave_Click(object sender, RoutedEventArgs e)
    {
        SaveFileDialog dlg = new SaveFileDialog();
        dlg.FileName = "UIElement File"; // Default file name
        dlg.DefaultExt = ".xaml"; // Default file extension
        dlg.Filter = "Xaml File (.xaml)|*.xaml"; // Filter files by extension

        // Show save file dialog box
        Nullable<bool> result = dlg.ShowDialog();

        // Process save file dialog box results
        if (result == true)
        {
            // Save document
            string filename = dlg.FileName;
            SerializeToXAML(myCanvas.Children, filename);
        }
    }

    private void btnLoad_Click(object sender, RoutedEventArgs e)
    {
        Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
        dlg.DefaultExt = ".xaml"; // Default file extension
        dlg.Filter = "Xaml File (.xaml)|*.xaml"; // Filter files by extension

        // Show open file dialog box
        Nullable<bool> result = dlg.ShowDialog();

        // Process open file dialog box results
        if (result == true)
        {
            string filename = dlg.FileName;
            UIElementCollection elements = DeSerializeXAML(filename) as UIElementCollection;

            // Add all child elements (lines, rectangles etc) to canvas
            myCanvas.Children.Clear();
            foreach (UIElement el in elements)
            {
                myCanvas.Children.Add(el);
            }
        }
    }

That works fine with serialization but when you deserialize, an exception is thrown.

Text of exception(translated with google):"You did not find a suitable constructor for the type" System.Windows.Controls.UIElementCollection.

"You can use the Arguments or FactoryMethod directives to generate this type.": Line number "1" and position in line "22".

A UIElementCollection instance is tied to a specific Visual , and as such, it is unsuitable for serialization (as @kostya-k points out). The deserialization logic doesn't know how to create a new UIElementCollection because it doesn't know which Visual to associate it with. And creating a new collection is pointless anyway, as you are simply transferring the values to myCanvas.Children .

The good news is that you can use a XamlObjectWriter to populate myCanvas.Children directly instead of instantiatating a new collection:

public static void DeSerializeXAML(UIElementCollection elements, string filename)
{
    var context = System.Windows.Markup.XamlReader.GetWpfSchemaContext();

    var settings = new System.Xaml.XamlObjectWriterSettings
                       {
                           RootObjectInstance = elements
                       };

    using (var reader = new System.Xaml.XamlXmlReader(filename))
    using (var writer = new System.Xaml.XamlObjectWriter(context, settings))
    {
        System.Xaml.XamlServices.Transform(reader, writer);
    }
}

private void btnLoad_Click(object sender, RoutedEventArgs e)
{
    Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
    dlg.DefaultExt = ".xaml"; // Default file extension
    dlg.Filter = "Xaml File (.xaml)|*.xaml"; // Filter files by extension

    // Show open file dialog box
    Nullable<bool> result = dlg.ShowDialog();

    // Process open file dialog box results
    if (result == true)
    {
        string filename = dlg.FileName;
        myCanvas.Children.Clear();
        DeSerializeXAML(myCanvas.Children, filename);
    }
}

UIElementCollection is not intended for serialization. It meant to be used when building a WPF visual tree.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM