2016-08-16 43 views
0

我的问题是MahApps.Metro和MahApps.Metro.IconPacks的嵌入式dll工作不正常。WPF MahApps.Metro嵌入式DLL资源不能正常工作

使用Visual Studio调试器来检查它们是否正在加载,它工作正常。如果它无法加载它们,程序会抛出一个xaml异常。

但由于某些原因,合并的ResourceDictionaries在运行时不起作用。

Should look like this

But looks like this

(正如你所看到的文字颜色是不同的,它缺少右侧的图标=>不加载的样式。)它看起来像

如果在程序的目录中提供了两个Dll,则为第一张图片。

我的App.xaml

<Application x:Class="Launcher.App" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:converter="clr-namespace:Launcher.Class.Converter" 
     > 

<Application.Resources> 
    <ResourceDictionary> 
     <ResourceDictionary.MergedDictionaries> 
      <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /> 
      <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" /> 
      <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" /> 
      <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" /> 
      <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" /> 
      <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/FlatSlider.xaml" /> 
      <ResourceDictionary Source="pack://application:,,,/MahApps.Metro.IconPacks;component/Themes/IconPacks.xaml" /> 
      <ResourceDictionary Source="Controls\ColorBrushes.xaml"/> 
      <ResourceDictionary Source="Controls\CustomMetroWindow.xaml"/> 
      <ResourceDictionary Source="Controls\CustomListView.xaml"/> 
      <ResourceDictionary Source="Controls\NewsStyle.xaml"/> 
      <ResourceDictionary Source="Controls\TextImageBox.xaml"/> 
      <ResourceDictionary Source="Controls\GlowMetroButton.xaml"/> 
      <ResourceDictionary Source="Controls\ToggleSwitchWin10.xaml"/> 
      <ResourceDictionary Source="Simple Styles.xaml"/> 
     </ResourceDictionary.MergedDictionaries> 
     <converter:InverseBooleanConverter x:Key="InverseBooleanConverter" /> 
     <converter:BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" /> 
     <converter:BooleanToVisibilityCollapsedConverter x:Key="BoolToVisibilityCollapsedConverter" /> 
     <converter:MultiObjectToBooleanConverter x:Key="MultiObjectToBooleanConverter" /> 
     <converter:DownloadProgressToVisibilityConverter x:Key="DownloadProgressToVisibilityConverter" /> 
     <converter:MultiObjectToStatusBarColorConverter x:Key="MultiObjectToStatusBarColorConverter" /> 
     <converter:MultiBooleanConverter x:Key="MultiBooleanConverter" /> 
     <converter:MultiBooleanToVisibilityConverter x:Key="MultiBooleanToVisibilityConverter" /> 
     <converter:OpacityToBooleanConverter x:Key="OpacityToBooleanConverter" /> 
    </ResourceDictionary> 
</Application.Resources> 

我的Program.cs

[STAThread] 
    public static void Main() 
    { 
     AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => 
     { 
      var resourceName = Assembly.GetExecutingAssembly().GetName().Name + ".Dll." + new AssemblyName(args.Name).Name + ".dll"; 
      if (!resourceName.Contains("resources")) 
      { 
       using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) 
       { 
        if (stream != null) 
        { 
         var assemblyData = new Byte[stream.Length]; 
         stream.Read(assemblyData, 0, assemblyData.Length); 
         return Assembly.Load(assemblyData); 
        } 
       } 
      } 
      else 
      { 
       Assembly requestedAssembly = args.RequestingAssembly; 
       AssemblyName requestedAssemblyName = new AssemblyName(args.Name); 
       while (true) 
       { 
        // requesting name in format: %assemblyname%.resources 
        // rewrite to: %assemblyName%.%assemblyName%.%culture%.resources.dll 
        // 
        var baseName = requestedAssemblyName.Name.Substring(0, requestedAssemblyName.Name.Length - ".resources".Length); 
        var name = string.Format("{0}.Dll.Lang.{1}.{2}.resources.dll", baseName, requestedAssemblyName.CultureInfo.Name, Assembly.GetExecutingAssembly().GetName().Name); 

        // by default for resources the requestingAssembly will be null 
        Assembly asm = null; 
        var assemblies = AppDomain.CurrentDomain.GetAssemblies(); 

        // resources have the same name as their belonging assembly, so find by name 
        var parentName = requestedAssemblyName.Name.Substring(0, requestedAssemblyName.Name.Length - ".resources".Length); 
        // I'd love to use linq here, but Cecil starts fucking up when I do (null reference exception on assembly.Write) 
        // without a Linq query it works fine, though 

        // ReSharper disable once LoopCanBeConvertedToQuery 
        foreach (var assembly in assemblies) 
        { 
         if (assembly.GetName().Name == parentName) 
         { 
          asm = assembly; 
         } 
        } 
        if (asm == null) 
        { 
         // cannot find assembly from which to load 
         return null; 
        } 
        using (var stream = asm.GetManifestResourceStream(name)) 
        { 
         if (stream != null) 
         { 
          var bytes = new byte[stream.Length]; 
          stream.Read(bytes, 0, bytes.Length); 
          return Assembly.Load(bytes); 
         } 
        } 
        // did not find the specific resource yet 
        // attempt to use the parent culture, this follows the .Net resource fallback system 
        // e.g. if sub resource de-DE is not found, then .Parent will be "de", if that is not found parent will probably be default resource 
        var fallback = requestedAssemblyName.CultureInfo.Parent.Name; 
        if (string.IsNullOrEmpty(fallback)) 
        { 
         // is empty if no longer a parent 
         // return null so .Net can load the default resource 
         return null; 
        } 
        var alteredAssemblyName = requestedAssemblyName.FullName; 
        alteredAssemblyName = alteredAssemblyName.Replace(string.Format("Culture={0}", requestedAssemblyName.CultureInfo.Name), string.Format("Culture={0}", fallback)); 

        requestedAssemblyName = new AssemblyName(alteredAssemblyName); 
       } 
      } 
      return null; 
     }; 

     App.Main(); 
    } 

控制

<TextBox x:Name="Username" 
      Controls:TextBoxHelper.Watermark="{lex:Loc Key=LoginWindow.YourUsername}" Margin="0,20,0,9" 
      Text="{Binding Config.AuthUsername}" 
      IsEnabled="{Binding LoggingIn, Converter={StaticResource InverseBooleanConverter}}" TextAlignment="Justify" 
      > 
      <TextBox.Resources> 
       <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource MetroTextImageBox}"> 
        <Setter Property="Controls:TextBoxHelper.ButtonTemplate"> 
         <Setter.Value> 
          <ControlTemplate TargetType="{x:Type ButtonBase}"> 
           <Grid Background="{TemplateBinding Background}"> 
            <Rectangle> 
             <Rectangle.Fill> 
              <VisualBrush> 
               <VisualBrush.Visual> 
                <iconPacks:PackIconModern Kind="User" Foreground="{StaticResource MainIconBrush}" /> 
               </VisualBrush.Visual> 
              </VisualBrush> 
             </Rectangle.Fill> 
            </Rectangle> 
           </Grid> 
          </ControlTemplate> 
         </Setter.Value> 
        </Setter> 
       </Style> 
      </TextBox.Resources> 
     </TextBox> 

回答

1

此代码的工作对我来说:(添加的所有库,嵌入式资源和集合tartup对象)

public class Program 
    { 
     private static Assembly ExecutingAssembly = Assembly.GetExecutingAssembly(); 
     private static string[] EmbeddedLibraries = 
      ExecutingAssembly.GetManifestResourceNames().Where(x => x.EndsWith(".dll")).ToArray(); 
     [STAThreadAttribute] 

     public static void Main() 
     { 

      AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; 

      App.Main(); 

     } 
     private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
     { 
      // Get assembly name 
      var assemblyName = new AssemblyName(args.Name).Name + ".dll"; 

      // Get resource name 
      var resourceName = EmbeddedLibraries.FirstOrDefault(x => x.EndsWith(assemblyName)); 
      if (resourceName == null) 
      { 
       return null; 
      } 

      // Load assembly from resource 
      using (var stream = ExecutingAssembly.GetManifestResourceStream(resourceName)) 
      { 
       var bytes = new byte[stream.Length]; 
       stream.Read(bytes, 0, bytes.Length); 
       return Assembly.Load(bytes); 
      } 
     } 
    } 
相关问题