WPF 中的 TextDecorationCollection 序列化

发布于 2024-10-30 20:52:14 字数 4205 浏览 0 评论 0原文

是否有任何 xaml 序列化属性可以为实际上是集合(TextDecorationCollection)的依赖属性指定?

我想使用序列化来克隆一个非常大且复杂的对象。这里是一个简化的代码示例:

有一个 MyVisualObject,它包含很多属性,包括我想要克隆的自定义字体 自

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class Export : Attribute
{
}

public class MyVisualObject : DependencyObject
{
    [Export]
    public CustomFont Font
    {
        get { return (CustomFont)GetValue(FontProperty); }
        set { SetValue(FontProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Font.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FontProperty =
        DependencyProperty.Register("Font", typeof(CustomFont), typeof(MyVisualObject));

    public MyVisualObject()
    {
        this.Font = new CustomFont();
    }
}

定义字体的定义如下:

public class CustomFont : DependencyObject
    {
        public TextDecorationCollection Decorations
        {
            get { return (TextDecorationCollection)GetValue(DecorationsProperty); }
            set { SetValue(DecorationsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TextDecorations.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DecorationsProperty =
            DependencyProperty.Register("Decorations", typeof(TextDecorationCollection), typeof(CustomFont), new UIPropertyMetadata(new TextDecorationCollection()));

        public CustomFont()
        {
            this.Decorations = System.Windows.TextDecorations.Underline;
        }
    }

深度克隆方法:

public static T DeepClone<T>(T from)
        {
            object clone = Activator.CreateInstance(from.GetType());

            Type t = from.GetType();
            System.Reflection.PropertyInfo[] pinf = t.GetProperties();

            foreach (PropertyInfo p in pinf)
            {
                bool serialize = false;

                foreach (object temp in p.GetCustomAttributes(true))
                {
                    if (temp is Export)
                    {
                        serialize = true;
                    }
                }

                if (serialize)
                {
                    string xaml = XamlWriter.Save(p.GetValue(from, null));                        
                    XmlReader rd = XmlReader.Create(new StringReader(xaml));
                    p.SetValue(clone, XamlReader.Load(rd), null);
                }                
            }

            return (T)clone;
        }

问题是每个当我将装饰初始化为下划线时,

this.Decorations = System.Windows.TextDecorations.Underline;

克隆过程崩溃并出现以下错误:“向‘System.Windows.TextDecorationCollection’类型的集合添加值引发了异常。”行号“1”和行位置“213”。

据我发现,序列化(这部分)

string xaml = XamlWriter.Save(p.GetValue(from, null));

返回一个 xaml,它没有将装饰设置为集合:

<CustomFont xmlns="clr-namespace:WpfApplication1;assembly=WpfApplication1" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <CustomFont.Decorations>
        <av:TextDecoration Location="Underline" /> 
    </CustomFont.Decorations>
</CustomFont>

但是如果 xaml 是这样的,则克隆过程将起作用:

<CustomFont xmlns="clr-namespace:WpfApplication1;assembly=WpfApplication1" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <CustomFont.Decorations>
        <av:TextDecorationCollection>
            <av:TextDecoration Location="Underline" /> 
        </av:TextDecorationCollection>
    </CustomFont.Decorations>
</CustomFont>

我找到了一个解决方法,带有字符串的东西替换:

xaml = xaml.Replace("<CustomFont.Decorations><av:TextDecoration Location=\"Underline\" /></CustomFont.Decorations>", "<CustomFont.Decorations><av:TextDecorationCollection><av:TextDecoration Location=\"Underline\" /></av:TextDecorationCollection></CustomFont.Decorations>");

但我认为它真的很脏,如果您可以提供更干净的解决方案(例如为 Decorations 属性指定一个属性),我将不胜感激

Is there any xaml serialization attribute that I can specify for a dependency property which actually is a collection (TextDecorationCollection)?

I want to use serialization for cloning a very large and complex object. Here a sample of the code, simplified:

There is a MyVisualObject, that contains a lot of properties, including a custom font, which I want to clone

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class Export : Attribute
{
}

public class MyVisualObject : DependencyObject
{
    [Export]
    public CustomFont Font
    {
        get { return (CustomFont)GetValue(FontProperty); }
        set { SetValue(FontProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Font.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FontProperty =
        DependencyProperty.Register("Font", typeof(CustomFont), typeof(MyVisualObject));

    public MyVisualObject()
    {
        this.Font = new CustomFont();
    }
}

And the custom font is defined like this:

public class CustomFont : DependencyObject
    {
        public TextDecorationCollection Decorations
        {
            get { return (TextDecorationCollection)GetValue(DecorationsProperty); }
            set { SetValue(DecorationsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TextDecorations.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DecorationsProperty =
            DependencyProperty.Register("Decorations", typeof(TextDecorationCollection), typeof(CustomFont), new UIPropertyMetadata(new TextDecorationCollection()));

        public CustomFont()
        {
            this.Decorations = System.Windows.TextDecorations.Underline;
        }
    }

THe deep clone method:

public static T DeepClone<T>(T from)
        {
            object clone = Activator.CreateInstance(from.GetType());

            Type t = from.GetType();
            System.Reflection.PropertyInfo[] pinf = t.GetProperties();

            foreach (PropertyInfo p in pinf)
            {
                bool serialize = false;

                foreach (object temp in p.GetCustomAttributes(true))
                {
                    if (temp is Export)
                    {
                        serialize = true;
                    }
                }

                if (serialize)
                {
                    string xaml = XamlWriter.Save(p.GetValue(from, null));                        
                    XmlReader rd = XmlReader.Create(new StringReader(xaml));
                    p.SetValue(clone, XamlReader.Load(rd), null);
                }                
            }

            return (T)clone;
        }

The problem is that each time I initialize the Decorations as Underline

this.Decorations = System.Windows.TextDecorations.Underline;

the cloning process crashes with this error:'Add value to collection of type 'System.Windows.TextDecorationCollection' threw an exception.' Line number '1' and line position '213'.

As far as I found out, the serialization, which is this part

string xaml = XamlWriter.Save(p.GetValue(from, null));

returns an xaml which does not have the decorations set as a collection:

<CustomFont xmlns="clr-namespace:WpfApplication1;assembly=WpfApplication1" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <CustomFont.Decorations>
        <av:TextDecoration Location="Underline" /> 
    </CustomFont.Decorations>
</CustomFont>

But the clone process would work if the xaml would be like this:

<CustomFont xmlns="clr-namespace:WpfApplication1;assembly=WpfApplication1" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <CustomFont.Decorations>
        <av:TextDecorationCollection>
            <av:TextDecoration Location="Underline" /> 
        </av:TextDecorationCollection>
    </CustomFont.Decorations>
</CustomFont>

I found a workaround, something with string replacements:

xaml = xaml.Replace("<CustomFont.Decorations><av:TextDecoration Location=\"Underline\" /></CustomFont.Decorations>", "<CustomFont.Decorations><av:TextDecorationCollection><av:TextDecoration Location=\"Underline\" /></av:TextDecorationCollection></CustomFont.Decorations>");

but I think it's really dirty, and I would apreciate it if you could provide a more clean solution (specifying an attribute for the Decorations property for example)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

十年不长 2024-11-06 20:52:14

您是否尝试过将以下属性应用于 Decorations 属性:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]

Have you tried applying the following attribute to the Decorations property:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文