【问题标题】:Assign property in XAML with a shorthand syntax without converters and markup extensions使用不带转换器和标记扩展的简写语法在 XAML 中分配属性
【发布时间】:2013-04-29 09:23:44
【问题描述】:

我有一个这样的 XAML

<ml:Visualizer Smooth="True" />

最近我们添加了不同类型的预处理,例如平滑、模糊、锐化等 现在我们这样写

<ml:Visualizer>
    <ml:Visualizer.Effect>
        <thirdParty:Smoothing/>
    </ml:Visualizer.Effect>
</ml:Visualizer>

是否可以将属性分配为 XML 属性,但可能无需编写自定义类型转换器或 MarkupExtensions。目标是为属性分配一个简短的语法,但实际效果可以稍后由第三方作为 DLL 提供,我们需要在 XAML 中引用它们。

<ml:Visualizer Effect="{thirdParty:Smoothing}" /> <!-- BUT WITH NO CUSTOM MARKUP EXTENSION -->

如果确实有可能,那么下一个级别将是设置效果的属性(即使只有一个默认构造函数可用)。

<ml:Visualizer Effect="{thirdParty:Smoothing Factor=5}" /> <!-- BUT WITH NO CUSTOM MARKUP EXTENSION -->

我知道它看起来像一个标记扩展,但是为每个引入的效果编写单独的标记扩展太乏味了。看起来太基本了,没有解决方案:)

有什么建议吗?

提前致谢!

【问题讨论】:

    标签: xaml


    【解决方案1】:

    完全可以在没有任何标记扩展的情况下做到这一点。 语法为SomeProp="{YourClass}"SomeProp="{YourClass Prop=Value}" 为 SomeProp 分配 YourClass 的一个实例。

    一个例子(在 .Net 4.0 上验证):

    <!-- Works with no markup extensions HardDriveExtension in the code! -->
    <Computer Storage="{HardDrive Gigabytes=2.5}"
        xmlns="clr-namespace:XamlExperiments;assembly=XamlExperiments"
      />
    
    
    using System.IO;
    using System.Xaml;
    using System;
    
    namespace XamlExperiments
    {
        class Program
        {
            static void Main(string[] args)
            {
                var xamlText =
                    @"<?xml version=""1.0"" encoding=""utf-8""?>
    <Computer Storage=""{HardDrive Gigabytes=2.5}""
        xmlns=""clr-namespace:XamlExperiments;assembly=XamlExperiments""
      />
    ";
    
                var computer = (Computer)XamlServices.Load(new StringReader(xamlText));
                computer.Process();
            }
        }
    
        public class Computer
        {
            public IStorage Storage { get; set; }
            public void Process() { Storage.Store();}
        }
    
        public interface IStorage
        {
            void Store();
        }
    
        public class HardDrive : IStorage
        {
            public double Gigabytes { get; set; }
            public void Store() {Console.WriteLine("Stored 1GB on HardDrive");}
        }
    }
    

    输出是: Stored 1GB on HardDrive

    请注意,无需任何标记扩展,您只需简单的{HardDrive Gigabytes=2.5} 即可实例化硬盘实例。

    【讨论】:

      【解决方案2】:

      如果您只需要知道要创建的对象的类型,可以使用现有的Type 标记扩展:

      Effect="{x:Type thirdParty:Smoothing}"
      

      或者,如果您需要对象的实例(这是您现有的标记正在创建的),您可以使用与转换器使用的方法类似的方法 - 即,将效果创建为资源,并引用它按名称:

      <Window.Resources>
           <thirdParty:Smoothing x:Key="myEffect" />
      </Window.Resources>
      ....
      <ml:Visualizer Effect="{StaticResource myEffect}" />
      

      【讨论】:

      • 不幸的是,我使用纯 System.Xaml(根本不涉及 WPF/SL),AFAIK 在这种情况下无法使用静态或动态资源功能。我想我要问的功能是一个不存在的“nice2have”速记语法,例如&lt;Item Storage="{|NiceStorage Capacity=2GB|}/&gt;
      • 也许IValueConverter 知道如何将您的字符串翻译成合适的对象?我可以看到它有效,但老实说,我怀疑多个自定义标记扩展会更有意义。
      【解决方案3】:

      您尝试实现的语法是为自定义标记扩展定义的语法,因此要求在没有语法的情况下执行此操作相当于要求在 C# 中调用 MyNonexistentMethod() 而不定义方法并期望它只执行您想要的操作.如果您只是想避免编写多个标记扩展,那么只需编写一个可以重复使用的。如果您可以使您的不同效果遵循通用模式(默认构造函数,接收参数的通用方式),那么您只需将类型和其他一些设置参数传递给您的标记扩展,并让它创建该类型的实例并设置参数为您提供任何当前或未来的类型。

      【讨论】:

      • 我明白你的意思,我问的语法只是没有退出。您的解决方法可以工作,但仍然有点多余&lt;Item Storage={Create {x:Type thirdParty:NiceStorage}, Arg1=2GB}
      • 在分配给 Type 属性时,x:Type 并不是绝对必要的,因为默认转换会处理它,但是通过使用它可以进行编译时检查非常好。
      • 令人惊讶的是,“MyNonexistentMethod()”确实存在。可能是 System.Xaml 带来的增强。 AFAIK 它确实在 WPF 3.5 中不存在。请在答案中找到更多详细信息。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-17
      • 1970-01-01
      • 2011-12-07
      • 2021-10-10
      • 2021-06-05
      • 2011-03-11
      相关资源
      最近更新 更多