0
我的问题是MahApps.Metro和MahApps.Metro.IconPacks的嵌入式dll工作不正常。WPF MahApps.Metro嵌入式DLL资源不能正常工作
使用Visual Studio调试器来检查它们是否正在加载,它工作正常。如果它无法加载它们,程序会抛出一个xaml异常。
但由于某些原因,合并的ResourceDictionaries在运行时不起作用。
(正如你所看到的文字颜色是不同的,它缺少右侧的图标=>不加载的样式。)它看起来像
如果在程序的目录中提供了两个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>