微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

MVVM / PRISM:对话框字符串应存储在哪里?

如何解决MVVM / PRISM:对话框字符串应存储在哪里?

我正在使用PRISM和MVVM构建应用程序。我有一个视图模型,该视图模型需要向用户显示一个非模式对话框,指示操作正在进行中。我实质上使用的是抽象的IDialogService。

我的问题是:该对话框中显示标题和消息的字符串应存储在哪里?视图模型的逻辑将导致对话框显示并确定何时关闭对话框。因此,我的视图模型中的代码如下所示:

let! closeDlgAction = 
            dialogSvc.ShowDialogModeless (
                "opening File","Please wait while your selected file is opened.") |>  Async.AwaitTask

我正在考虑本地化方案。 WPF具有通过资源字典等提供本地化的机制。这些字符串似乎属于资源字典,但是视图模型不应依赖WPF资源目录-尤其是因为相同的视图模型将稍后在Xamarin Forms应用程序上使用。

想到的最好的解决方案是使用一种将资源库抽象化的服务(例如IDialogStringService),但我想知道是否有更好或更优选的方法

解决方法

您不应使用资源字典(xaml)来存储文本。相反,您必须使用资源(* .resx)。在VS中:

  1. 右键单击项目
  2. 添加->新项目...
  3. 找到“资源文件”模板,键入名称,然后单击“添加”
  4. 选择。打开此文件(将打开特殊编辑器),如果要从另一个项目或XAML访问文本,请在顶部栏将“访问修饰符”切换为“公共”。添加一些键\值字符串。
  5. 右键单击资源文件,然后单击运行自定义工具。新类将使用静态属性生成,其名称基于步骤4中的键。

使用方法(如果文件的名称为Localizations.resx,并且字符串的键为“ AppTitle”)

来自代码:

let! closeDlgAction = 
            dialogSvc.ShowDialogModeless (
                Localizations.AppTitle,"Please wait while your selected file is opened.") |>  Async.AwaitTask

来自xaml:

<Window
    x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="{x:Static Localizations.AppTitle}"/>
生成的

*。resx文件和* .cs文件都不依赖于任何WPF程序集,因此您可以在不同的程序集中使用它们:在共享视图模型中,从wpf视图和从xamarin视图中。只需将* .resx文件放在单独的netstandard程序集中,并在需要它的位置引用它即可 enter image description here

这种方式的缺点:

  1. resx用字符串生成类,每个字符串都是公共属性,因此静态代码分析有效
  2. 您没有添加新的抽象级别
  3. 您可以引用代码文件或XAML中的字符串
,

我喜欢Vadim的回答,并且我以前使用过这种方法。如果我的视图模型与WPF项目位于同一项目中,那将是最佳解决方案。

但是,我的视图模型在不同的库(和不同的语言)中,并且将在Prism MVVM WPF项目和Prism MVVM Xamarin Forms项目之间共享。我仍然可以使用View Model库中的资源,但是本地化方面的顾虑将分别存在于WPF项目(用于Views)和View Model库中。 IMO对本地化的关注应该集中。

因此,我决定抽象出服务背后的资源。事实证明,实现资源服务比我想象的要简单得多。为了直观地使用索引器,我定义了一个由IResourceService返回的“资源容器对象”,如下所示:

public struct ResourceContainer
{
    private readonly Func<string,string> _resourceGetter;

    public string this[string resourceId] => _resourceGetter(resourceId);

    public ResourceContainer(Func<string,string> resourceGetter) => _resourceGetter = resourceGetter;
}

public interface IResourceService
{
     ResourceContainer Resources { get; }
}   

WPF库中的服务实现如下:

 public class ResourceService : IResourceService
{
    public ResourceService()
    {
        Resources = new ResourceContainer((s) => Application.Current.Resources[s] as string);
    }

    public ResourceContainer Resources { get; }
}

在WPF层的XAML资源目录中:

<s:String x:Key="FileOpenDialogTitle">Opening File</s:String>
<s:String x:Key="FileOpenDialogMessage">Please wait while your selected file is opened.</s:String>

最后,视图模型通过在其构造函数上请求IResourceService来消耗此服务,其用法如下:

 let! closeDlgAction = 
            dialogSvc.ShowDialogModeless (
                resourceSvc.Resources.["FileOpenDialogTitle"],resourceSvc.Resources.["FileOpenDialogMessage"]) |> Async.AwaitTask

此方法最终将需要实施两次资源-一次用于WPF项目,一次用于XF项目,但是无论如何,我必须两次实施视图。至少在这两种情况下,本地化的关注点都是集中的(或者两个项目之间都可以使用共享的资源库)。

编辑:通过将本地化资源(.resx)放在WPF项目中,该技术还可以利用Vadim的建议,或者让XAML资源目录引用静态资源,或者让ResourceService直接返回资源。拥有.resx格式的资源可能会使在多个项目之间共享它们更加直接。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。