2

My problem is shown in the following program, where the GeometryModel3D's Material is set from a StaticResource in XAML.

Is it possible to get the XamlWriter to save out the actual StaticResources instead of the resolved references (which it does now)? If so, what do I need to do?

using System;
using System.IO;
using System.Text;
using System.Windows.Controls;
using System.Windows.Markup;

namespace MaterialTest
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            string xaml = "";
            xaml += "<Viewport3D xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>";
            xaml += "  <Viewport3D.Resources>";
            xaml += "    <DiffuseMaterial x:Key='Steel' />";
            xaml += "  </Viewport3D.Resources>";
            xaml += "  <ModelVisual3D>";
            xaml += "    <ModelVisual3D.Content>";
            xaml += "      <GeometryModel3D Material='{StaticResource Steel}'>";
            xaml += "        <GeometryModel3D.Geometry>";
            xaml += "          <MeshGeometry3D Positions='-0.5,-0.5,0 0.5,-0.5,0 0.5,0.5,0 -0.5,0.5,0' TriangleIndices='0 1 2 0 2 3' />";
            xaml += "        </GeometryModel3D.Geometry>";
            xaml += "      </GeometryModel3D>";
            xaml += "    </ModelVisual3D.Content>";
            xaml += "  </ModelVisual3D>";
            xaml += "</Viewport3D>";

            MemoryStream buffer = new MemoryStream(Encoding.UTF8.GetBytes(xaml));
            Viewport3D viewport = XamlReader.Load(buffer) as Viewport3D;

            string xaml_out = XamlWriter.Save(viewport);
        }
    }
}
Vimes
  • 10,577
  • 17
  • 66
  • 86
Kevin Marshall
  • 301
  • 3
  • 8

2 Answers2

1

Is it possible to get the XamlWriter to save out the actual StaticResources instead of the resolved references (which it does now)?

No, I am afraid it's not. This is a known limitation of XamlWriter.Save that is documented on MSDN: https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/serialization-limitations-of-xamlwriter-save

Common references to objects made by various markup extension formats, such as StaticResource or Binding, will be dereferenced by the serialization process. These were already dereferenced at the time that in-memory objects were created by the application runtime, and the Save logic does not revisit the original XAML to restore such references to the serialized output.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • Thank you for replying. I guess I was hoping there was some advanced functionality which facilitated the XamlWriter writing out Static Resources. I guess I just have a hard time believing that the standard XamlWriter can't manage writing out static resources. I guess my approach will now be to create the Xaml with the XamlWriter and manage the Static Resources in a post process step with an Xml parser:( – Kevin Marshall Aug 29 '17 at 20:27
0

I had the same issue with Bindings before and I found the solution to serialize bindings in this link: Binding Serialization

And, based on this solution i found out how to "filter" the Style serialization.

Define what a Style returns when it gets to be serialized, StyleConverterClass:

class StyleConverter : System.Windows.ExpressionConverter
    {
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(MarkupExtension))
                return true;
            else return false;
        }
        public override object ConvertTo(ITypeDescriptorContext context,
                                         System.Globalization.CultureInfo culture,
                                         object value, Type destinationType)
        {
            if (destinationType == typeof(MarkupExtension))
            {
                Style style = value as Style;
                if (style == null)
                    throw new Exception();

                foreach (var dictionarys in ((MetroWindow)Application.Current.MainWindow).Resources.MergedDictionaries)
                {                    
                    foreach (DictionaryEntry entry in dictionarys)
                    {
                        if (entry.Value is Style && (entry.Value as Style) == style)
                        {
                            return new StaticResourceExtension(entry.Key);
                        }
                    }
                }
                
                return style;
            }

            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

Important thing to notice is the use of StaticResourceExtension class.

Then, just make a new registration:

EditorHelper.Register<Style, ExpressionConverter.StyleConverter>();

And voilá, when a Style gets to be serialized, it will return an instance of StaticResourceExtension and not a Style instance, and so, avoiding writing the whole Style description into the exported xaml. An exported component's Style will look like this:

<cuc:ComboBoxWrapper IsDropDownOpen="False" Style="{av:StaticResource
ResourceKey=MahApps.Styles.ComboBox.Virtualized}" av:Grid.Column="0"
av:Grid.Row="1" />
Zoe
  • 27,060
  • 21
  • 118
  • 148