我在一个Silverlight应用程序中使用prism框架,在单独的XAP中有多个模块。
我在我的shell项目中定义了一个资源字典。在我的模块中,我可以很好地使用资源,但由于模块与shell分离,直到它们在运行时加载,设计器不会显示它们或识别它们。
有没有办法让模块在设计时知道我的资源而不在每个视图xaml中合并我的资源文件?
我的资源文件位于“常见”项目中。
答案 0 :(得分:5)
我认为我肯定有设计时资源的解决方案。
<强>优点:强>
让我们考虑以下解决方案:
您可以在MyApp.Common中定义画笔,隐式样式,模板等。
使用我的 SharedResourceDictionary 在所有项目中包含ResourceDictionary。在设计时,它将为每个设计器加载ResourceDictionary,在运行时,ResourceDictionary将仅在必要时加载。
用法示例:
在App.xaml中包含SharedResourceDictionary
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<common:SharedResourceDictionary SharedSource="MyApp.Common;component/CommonResources.xaml" />
</ResourceDictionary>
</Application.Resources>
包括SharedResourceDictionary无处不在设计师找不到 一些共享资源,例如在MyApp.Module1 / UserControl1.xaml
中<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;
}
}
答案 1 :(得分:4)
我发现有几个解决方案:
1)创建模块项目时,将App.xaml保留在项目中而不是删除它,并在那里实例化资源,就好像它本身就是它自己的应用程序一样(你也可以添加一个新的Application类)该项目,如果你已经删除它)。当您的模块加载到shell中时,该文件将被忽略,因此它基本上只在设计时有效。这在视觉工作室和混合中效果很好,但如果你有很多模块,内存占用可能会成为一个问题。
2)使用设计时资源。有关在此设置此内容的一些信息:http://adamkinney.com/blog/2010/05/04/design-time-resources-in-expression-blend-4-rc/。这仅提供混合支持,您的视图将被删除视觉工作室中的所有样式和格式。这对我来说并不理想,因为我喜欢在visual studio中处理UI的某些方面。似乎也没有记录的手动设置设计时资源的方法。
答案 2 :(得分:2)
将资源从Shell迁移到共享工具并使设计师工作得很好的小型自我体验指南
基于阅读此类问题并在相同/类似问题上搜索互联网的一些想法。我写这个主要是因为问题2(下面),这与这个问题有关,恕我直言。
所以,我们有相同的设计,所有的风格和资源都在壳牌。这产生了两个问题:
因此我们将所有样式迁移到共享程序集(参考资料)。
要解决第一个问题,你需要像Liero建议的那样,即为每个UserControl添加资源字典。我没有尝试他的SharedDictionary,但正常的ResourceDictionary肯定会带回上下文帮助并删除蓝色下划线。然而,设计师仍未正确显示。
所以第二个问题。在描述in this article的设计时,有一个小技巧可以为设计师带来样式。基本上,您将名为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
”。 “;assembly=Resources
” - 您应该删除的部分,因为它现在是相同的程序集。我们已经在UserControls中处理了一些本地资源,如下所示:
<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>
答案 3 :(得分:1)
如果您希望为观看次数提供设计时数据,我建议您阅读this article。它显示了如何使用Blend在项目中创建设计时间数据,该数据未包含在应用程序的发布版本中。
希望它有所帮助。