1

我正在尝试通过 Windows 8 Metro C# App 中的反射加载自定义控件库,该库已加载但未加载 generic.xaml 中指定的样式,最终我尝试通过将 generic.xaml 设为嵌入式资源来加载它然后,将 Generic.xaml 提取到一个位置并将其位置指定为 ResourceDictionary 对象的 uri,但它会引发错误

"Failed to create a 'System.Type' from the text local:CustomControl1"

我无法创建 nuget 包或扩展 SDK,因为不幸的是,这不是我的要求,下面是我编写的示例代码,用于复制 generic.xaml 并将其加载到资源字典中

public sealed class CustomControl1 : Control
{
    public CustomControl1()
    {
        this.DefaultStyleKey = typeof(CustomControl1);
        Assembly CurrentAssembly = typeof(CustomControl1).GetTypeInfo().Assembly;
        var names = CurrentAssembly.GetManifestResourceNames();
        var stream = CurrentAssembly.GetManifestResourceStream(names.First());
        //generic.xaml is an embedded resource in the current assembly
        if (stream != null)
        {
            //created new generic.xaml here
            var file = ApplicationData.Current.LocalFolder.CreateFileAsync("Generic.xaml", CreationCollisionOption.ReplaceExisting).Completed = (o, a) =>
            {
                var storageFile = o.GetResults();

                var s = storageFile.OpenStreamForWriteAsync().Result;

                var length = (int)stream.Length;
                byte[] bytes = new byte[length];
                int output = stream.Read(bytes, 0, length);

                s.Write(bytes, 0, length);
                s.Flush();
                s.Dispose();

                var asyncResult = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                {
                    var resourceDict = new ResourceDictionary();
                    var uri = new Uri("ms-appdata:///local/" + storageFile.Name);
                    resourceDict.Source = uri;
                });
            };
        }
    }


    // OnApplyTemplate is not called without loading the style from generic.xaml
    protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
    }
}

下面的代码是我在自定义控件库的构造函数中写的,这样就可以不用generic.xaml来设置控件模板了

在这里,由于属性 TargeType="local:CustomControl1" 不存在,因此控件被正确加载,因为我在构造函数中加载了样式,所以调用 OnApplyTemplate

StringBuilder sb = new StringBuilder();
sb.Append(@"<ControlTemplate  
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""   
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""  
xmlns:d=""http://schemas.microsoft.com/expression/blend/2008""
xmlns:mc=""http://schemas.openxmlformats.org/markup-compatibility/2006"">");
sb.Append(@"<Border Background=""{TemplateBinding 
Background}""                                                             
BorderBrush=""{TemplateBinding BorderBrush}""
BorderThickness=""{TemplateBinding BorderThickness}"">
   <Grid>
      <Button x:Name=""Tbx1"" Content=""Hello World"" Foreground=""HotPink""   
       HorizontalAlignment=""Stretch"" VerticalAlignment=""Stretch""/>
  </Grid>
</Border>");
sb.Append(@"</ControlTemplate>");
this.Template = (ControlTemplate)XamlReader.Load(sb.ToString());

但问题是使用 XamlReader 加载所有样式不是一个好主意,除非我们没有选项。因为可能有各种依赖样式也必须加载。

4

1 回答 1

1

在WinRTXamlToolkit中查看他们是如何做到的。他们Generic.xaml为项目创建了所有控件模板,并将所有控件模板包含在不同样式中的不同样式中,这些样式ResourceDictionary打包在各个控件旁边。

更简单地说(对于模板化控件,就像您正在使用的那样):

  • 为每个控件制作两个文件,MyControl.cs然后MyControl.xaml

  • MyControl.cs您的MyControl构造函数中,将 设置StyleKeytypeof(MyControl)(就像您当前所做的那样)。

  • 确保控件的样式TargetType设置为控件的类型。ControlTemplate对 . 中设置的Template属性执行相同的操作Style

  • MyControl.xaml中,制作一个ResourceDictionary存储所有必要样式、模板和资源的文件。

  • 在您的中,在根目录下Generic.xaml创建一个标签并为每个控件创建一个,将 Source 设置为MergedDictionariesResourceDictionaryMyControl.xaml

将每个 .xaml 文件设置为构建类型PageCustomTool设置为MSBuild:Compile.

希望这会有所帮助,祝您编码愉快!

于 2014-02-05T23:24:43.637 回答