是否有一种方法可以使模块在设计时意识到我的资源,而不必在每个视图XAML中合并我的资源文件? 我的资源文件位于“common”项目中。
我认为我有一个设计时资源的绝佳解决方案。
好处:
让我们考虑以下解决方案:
您可以在MyApp.Common中定义brushes、隐式样式、模板等。
使用我的SharedResourceDictionary将ResourceDictionary包含在所有项目中。在设计时,它将为每个设计器加载ResourceDictionary,在运行时,只有在必要时才会加载ResourceDictionary。
使用示例:
在App.xaml中包含SharedResourceDictionary
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<common:SharedResourceDictionary SharedSource="MyApp.Common;component/CommonResources.xaml" />
</ResourceDictionary>
</Application.Resources>
在设计器无法找到某些共享资源的情况下,例如在MyApp.Module1 / UserControl1.xaml中,需要在各处包含SharedResourceDictionary。
<UserControl.Resources>
<common:SharedResourceDictionary SharedSource="MyApp.Common;component/CommonResources.xaml" />
</UserControl.Resources>
来源:
/// <summary>
/// Loads singleton instance of ResourceDictionary to current scope;
/// </summary>
public class SharedResourceDictionary : ResourceDictionary
{
/// <summary>
/// store weak references to loaded ResourceDictionary, to ensure that ResourceDictionary won't be instanciated multiple times
/// </summary>
protected static Dictionary<string, WeakReference> SharedResources = new Dictionary<string, WeakReference>();
public string SharedSource
{
get { return _SharedSource; }
set
{
if (_SharedSource != value)
{
_SharedSource = value;
sharedSourceChanged();
}
}
}
private string _SharedSource;
private void sharedSourceChanged()
{
//ResourceDictionary will be instanciated only once
ResourceDictionary sharedResourceDictionary;
lock (SharedResources)
{
WeakReference weakResourceDictionary = null;
if (SharedResources.ContainsKey(_SharedSource))
{
weakResourceDictionary = SharedResources[_SharedSource];
}
else
{
SharedResources.Add(_SharedSource, null);
}
if (weakResourceDictionary == null || !weakResourceDictionary.IsAlive) //load ResourceDictionary or get reference to exiting
{
sharedResourceDictionary = (ResourceDictionary)Application.LoadComponent(new Uri(_SharedSource, UriKind.Relative));
weakResourceDictionary = new WeakReference(sharedResourceDictionary);
}
else
{
sharedResourceDictionary = (ResourceDictionary)weakResourceDictionary.Target;
}
SharedResources[_SharedSource] = weakResourceDictionary;
}
if (Application.Current != null)
{
//if sharedResourceDictionary is defined in application scope do not add it to again to current scope
if (containsResourceDictionary(Application.Current.Resources, sharedResourceDictionary))
{
return;
}
}
this.MergedDictionaries.Add(sharedResourceDictionary);
}
private bool containsResourceDictionary(ResourceDictionary scope, ResourceDictionary rs)
{
foreach (var subScope in scope.MergedDictionaries)
{
if (subScope == rs) return true;
if (containsResourceDictionary(subScope, rs)) return true;
}
return false;
}
}
将资源从Shell迁移到共享程序集并使设计师正常工作的小型个人经验指南
基于阅读类似问题和在互联网上搜索同样/类似问题的一些想法。我主要是因为问题2(下面)与此问题有关,所以才写这篇文章。
所以,我们拥有相同的设计,所有样式和资源都在Shell中。这产生了两个问题:
因此,我们将所有样式迁移到共享程序集(资源)中。
要解决第一个问题,您需要像Liero建议的那样添加每个UserControl的资源字典。我没有尝试过他的SharedDictionary,但普通的ResourceDictionary绝对可以恢复上下文帮助并删除蓝色下划线。然而,设计师仍然无法正常显示。
所以第二个问题。有一个小技巧可以在设计时将样式带到设计师中,只需参考这篇文章即可。基本上,您需要将名为DesignTimeResources.xaml的资源字典添加到您的项目中,其中包含对您的资源的引用:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Resources;component/Themes/Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
然后将其移动到Properties文件夹。然后手动编辑项目文件并将此文件的项目更改为:
<Page Include="Properties\DesignTimeResources.xaml" Condition="'$(DesignTime)'=='true' OR ('$(SolutionPath)'!='' AND Exists('$(SolutionPath)') AND '$(BuildingInsideVisualStudio)'!='true' AND '$(BuildingInsideExpressionBlend)'!='true')">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
<ContainsDesignTimeResources>true</ContainsDesignTimeResources>
</Page>
基本上,这是一个文件,如果您添加设计时资源,Blend将生成它。VS不能创建它,但可以很好地读取它。编辑项目文件表示您不想在发布中使用此文件。
这里还有两个小问题,也许会帮助某些人。
clr-namespace:XXX;assembly=Resources
". The ";assembly=Resources
"-part you should delete, as it is the same assembly now.We already head some local resources in our UserControls, like this:
<UserControl.Resources>
<PresentationHelpers:BoolToVisibilityConverter x:Key="boolToVisibilityConverter" />
</UserControl.Resources>
一开始,我只是将新的ResourceDictionary添加到这个块中,它要求我提供一个x:Key。我习惯于直接将资源添加到UserControl.Resources中,所以我没有意识到为了合并另一个字典,你需要使用<ResourceDictionary>
标签,而这通常是可以省略的。因此,它看起来像这样:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<Helpers:RedbexResourceDictionary Source="pack://application:,,,/Resources;component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
<PresentationHelpers:BoolToVisibilityConverter x:Key="boolToVisibilityConverter" />
</ResourceDictionary>
</UserControl.Resources>