在不依赖 App.xaml 的情况下使用用户控件中的资源的方法



我将一个应用程序转换为DLL库,其中我的主窗口成为用户控件。我正在使用手动创建System.Windows.Application对象来存储我的资源的方法,但我想摆脱它并让我的用户控制自给自足,所以我可以简单地执行以下操作:

CustomUserControl control = new CustomUserControl ( object_to_pass);

然后,它将在内部处理其他所有事情。控件的基本布局是承载多个页面的框架,如向导样式的应用。

我有两个主要问题:

设置对视图模型的引用

我认为,我将在用户控件类上使用类似的函数,并通过单例传递对用户控件的引用,而不是使用我广泛使用的System.Windows.Application.FindResource

为此,我在一个名为"ViewModelLocator"的类中使用了mvvm-light的SimpleIoc容器来跟踪所有视图模型。问题是,这是从用户控件的数据上下文绑定加载App.xaml的资源。

这不能再这样做了,因为用户控件本身必须在自己的 xaml 中进一步实例化包含它的资源:

<UserControl x:Class="WUP.Views.WarmUpPluginUserControl"
mc:Ignorable="d"
...
...
<!--This will not work-->
DataContext="{Binding Source={StaticResource Locator}, Path=MainWindowLogic}">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Path/To/ViewModelLocator/Resource.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>

现在,我必须在用户控件代码中实例化 ViewModel 定位器,并将其设置为具有Resources.Add的资源。这迫使我从所有其他视图(页面)切换到对 ViewModel 定位器的所有引用的动态资源。这不仅会导致进一步描述的问题,而且很丑陋,因为我无法再像以前那样使用路径访问成员函数:

DataContext="{Binding Source={StaticResource Locator}, Path=MainWindowLogic}">

从 xaml 引用资源,动态与静态

我使用的资源是画笔、颜色、模板和转换器,每个资源都在各自的资源字典中,我以正确的顺序添加它们以避免依赖问题。

第一部分中的方法适用于通过引用单一实例中的用户控件从 ViewModel 访问资源。现在的问题是如何在应用程序的每个视图中加载资源。我尝试了将它们全部粘贴Page.ResourcesUseControl.Resources的蛮力方法,但这给了我资源,尽管它们存在于某些页面中,但在某些页面中没有发现错误。我正在调查为什么会发生这种情况,但我不确定

然后,我尝试了 Dr.WPF 创建单例类的方法,您可以使用该方法创建资源的单个实例并将它们公开为依赖属性。这迫使我再次对我的所有视图使用动态资源。

这对于除转换器以外的所有资源都很好,并且我收到最初以这种方式引用的所有转换器的错误:

Visibility="{Binding Functions.DictatesActions, Converter={StaticResource BooleanToVisibilityConverter}, UpdateSourceTrigger=PropertyChanged}"

所以我不知道如何处理这是动态场景。

我正在认真考虑放弃这种方法,只使用System.Windows.Application来存储我的所有资源,尽管它可能会导致托管应用程序 (winforms) 中的其他用户控件出现问题。如果有更好的方法,请告诉我!

我终于设法解决了我的问题:

设置对视图模型的引用

在这里,我只需要从后面的代码中完成所有操作。正如我所提到的,我使用 ViewModelLocator 来跟踪我的所有 VM,因此我将引用设置为实际用户控件构造函数中的资源:

Resources["Start"] = view_model_locator.Start;
Resources["SelectUnit"] = view_model_locator.SelectUnit;
Resources["HardwareChecks"]  = view_model_locator.HardwareChecks;
Resources["ConfigurationChecks"] = view_model_locator.ConfigurationChecks;
...

然后,我将对 ViewModel 定位器中的用户控件的引用作为静态属性包含在内:

ViewModelLocator.WarmUpPluginUserControl = this;

然后我可以像这样从其代码中的其他视图访问它:

DataContext = ViewModelLocator.WarmUpPluginUserControl.FindResource("Start");     

我也可以在 VM 中使用它,就像我使用 Application.Current.FindResource() 一样。这不是最优雅的解决方案,但它奏效了

从 xaml 引用资源,动态与静态

在这里,我坚持使用蛮力方法,将所有资源包含在每页顶部:

<WUP:WUPPage.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/WarmUpPlugin;component/Resources/Colors.xaml"/>
<ResourceDictionary Source="pack://application:,,,/WarmUpPlugin;component/Resources/Styles.xaml"/>
...
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

这确实在开始时给我带来了问题,因为我有资源没有发现错误,但这是由于我的一些词典有依赖其他词典,所以我不得不通过合并词典将它们添加到相关词典中。

当应用程序独立时,我没有注意到此依赖项问题,因为所需的所有资源都已加载到应用程序范围内。

我打算将其替换为 Dr WPF 方法,但我仍然必须将所有 XAML 引用从静态更改为动态,然后处理无法通过动态资源引用访问的转换器。

最新更新