我最近在WPF中编程很多,但我的View和ViewModel在这一点上并不是分开的.嗯,这是部分原因.我的所有绑定都与文本框中的文本,标签内容,数据网格中的列表,......相关,都是由常规属性完成的,其中包含NotifyPropertyChanged事件.
处理按钮点击或文本更改内容的所有事件都是通过链接事件来完成的.现在,我想开始使用命令并找到这篇文章:http://www.codeproject.com/Articles/126249/MVVM-Pattern-in-WPF-A-Simple-Tutorial-for-Absolute.它解释了如何设置MVVM,但我对它感到困惑RelayCommand.
它做了什么工作?它对我表单中的所有命令都可用吗?如果(a)某些文本框未填写,如何禁用该按钮?
编辑1:
对"我的表单中的所有命令都可用吗?"的一个很好的解释.在这里回答:https://stackoverflow.com/a/22286816/3357699
这是我到目前为止的代码:https://stackoverflow.com/a/22289358/3357699
我有一个类来处理我的应用程序的本地化.我的目标是该类可以在整个应用程序中使用,因此我将其设置为静态.这允许我在我的应用程序的任何地方调用下面的代码.
Localizer.GetString(/* Key to localize */)
Run Code Online (Sandbox Code Playgroud)
该方法使用Localizer类中的几个字段.为确保设置这些字段,Init添加了一个方法来初始化Localizer.如果我的类的用户忘记调用Init例如应用程序的启动,则会发生异常,因为未设置字段.
我正在考虑的一个解决方案是使Localizer类不是静态的,添加一个构造函数来设置字段并static class在我的应用程序中的全局中初始化类,如下所示:
public static class Globals
{
public static Localizer Localize = new Localizer(/* Field arguments here */);
}
Run Code Online (Sandbox Code Playgroud)
现在我不确定最好的方法是什么.或
Init在使用该类之前调用.还有一点需要注意:用户无权访问该类的来源.
ResourceDictionaries我的应用程序中有几个可以使其可本地化.这些文件的名称类似于Language_en.xaml,Language_nl.xaml等.下面给出了这种文件的一个例子.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<!-- DO NOT LOCALIZE -->
<system:String x:Key="Language">English</system:String>
<FlowDirection x:Key="FlowDirection">LeftToRight</FlowDirection>
<!-- DO LOCALIZE -->
<system:String x:Key="Title">English Title External</system:String>
</ResourceDictionary>
Run Code Online (Sandbox Code Playgroud)
要在应用程序运行时加载这些文件,我创建如下路径:
_appResDicSource = Path.Combine("\\" + _projectName + ";component", _languagesDirectoryName,
_fileBaseName + "_" + language + ".xaml");
_clsLibResDicSource = "\\MyDLL;component\\Languages\\Language_" + language + ".xaml";
Run Code Online (Sandbox Code Playgroud)
以上内容适用于构建操作Resource和PageCtOD设置为"不复制",自定义工具设置为"MSBuild:编译".
从这个链接我学到了下面的引用,但对我的项目来说最好的是什么?
资源(仅限wpf):将文件嵌入共享(由具有类似设置的程序集中的所有文件)组装清单资源,名为AppName.g.resources.
Page(仅限wpf):用于将xaml文件编译为baml.然后使用与Resource相同的技术嵌入baml(即可用作'AppName.g.resources)
我正在尝试上班的应用程序使用MVVM.这篇文章的最大部分是对我尝试过的内容和我工作的内容的解释.问题接近帖子的底部.使用的Localizer类仅在此处用作示例,并且可以很容易地用另一个类替换.
我有class library一个Localizer班级.此类的目的是即时更改应用程序的语言,而无需重新启动应用程序.`Localizer必须先实例化才能使用,但一旦实例化,就应该可以在整个应用程序中使用.(该类使用应用程序资源来本地化应用程序.)
我的第一个方法我能想到的是制作的Localizer一个public static class带一个public static void Initialize方法.这样我可以初始化Localizer这样的
Localizer.Initialize(/* Needed arguments here */);
Run Code Online (Sandbox Code Playgroud)
在应用程序级别,并在我的类库或这样的应用程序中的任何地方使用它
string example = Localizer.GetString(/* A key in the resource dictionary */);
Run Code Online (Sandbox Code Playgroud)
考虑到类库是由我编写的(只有我有源代码)并且被其他人使用,他们对源代码一无所知(他们只知道类库可以做什么),我必须在某种情况下明确说明他们需要Localizer.Initialize在应用程序级别调用"如何使用此类库",以便在应用程序的任何位置使用它.
经过一些研究后,很多人都说这是一个不好的做法,并建议研究什么是依赖注入(DI)和控制反转(IoC),所以我做了.我了解到DI与我的第一种方法大致相同,但删除静态内容,Localizer.Initialize用作构造函数并在其他类中注入实例化类.
所以第二种方法是依赖注入,这就是我被困住的地方.我设法让我的应用程序使用单个代码进行编译,MainWindowView并MainWindowViewModel使用以下代码:
protected override void OnStartup(StartupEventArgs e)
{
ILocalizer localizer = new Localizer(Current.Resources, System.Reflection.Assembly.GetExecutingAssembly().GetName().Name, "Languages", "Language", "en");
var mainWindowViewModel = new MainWindowViewModel(localizer); …Run Code Online (Sandbox Code Playgroud) 我有一个ChangeLanguage类库中的公共方法,应该被其他人使用,他们不知道源代码是什么,但知道它可以做什么.
public string ChangeLanguage(string language)
{
#if DEBUG
// Check if the new language is not null or an empty string.
language.ThrowArgumentNullExceptionIfNullOrEmpty("language", GetString("0x000000069"));
#else
if (string.IsNullOrEmpty(language))
language = _fallbackLanguage;
#endif
}
Run Code Online (Sandbox Code Playgroud)
对我来说,检查是否language实际传递给方法看起来很明显,如果没有,则向开发人员抛出错误.这是一个非常小的性能损失,我认为最好不抛出异常,但只是在没有提供语言时使用后备语言.
我想知道这是一个好的设计方法,如果我应该继续在库中的其他地方使用它,就像这里:
_appResDicSource = Path.Combine("\\" + _projectName + ";component", _languagesDirectoryName, _fileBaseName + "_" + language + ".xaml");
_clsLibResDicSource = "\\Noru.Base;component\\Languages\\Language_" + language + ".xaml";
ResourceDictionary applicationResourceDictionary;
ResourceDictionary classLibraryResourceDictionary;
try { applicationResourceDictionary = new ResourceDictionary { Source = new Uri(_appResDicSource, UriKind.RelativeOrAbsolute) }; }
catch
{
#if …Run Code Online (Sandbox Code Playgroud) 我有Class Library以下代码位。
以下是我UserControl的Resource:
<UserControl.Resources>
<ResourceDictionary Source="pack://application:,,,/Mine.Controls;component/Templates.xaml" />
</UserControl.Resources>
Run Code Online (Sandbox Code Playgroud)
下面是我的ResourceDictionary名为Templates.xaml 的文件:
构建操作:资源
复制到...:不要复制
自定义工具:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ControlTemplate x:Key="MyButton"
TargetType="Button">
<Border x:Name="buttonBorderOuter"
BorderBrush="#DBDBDB"
BorderThickness="1"
Background="#00ECECEC"
CornerRadius="5" />
</ControlTemplate>
</ResourceDictionary>
Run Code Online (Sandbox Code Playgroud)
然后我得到错误
异常:查找资源字典“pack://application:,,,/Mine.Controls;component/Templates.xaml”时发生错误。
我究竟做错了什么?
我正在开发一个应用程序,我想知道我是否应该使用Enumwith a StringValueAttributevs a classwith properties。
我的第一种方法是Enum使用StringValueAttribute. 这是我现在使用的方法。通过一种叫做GetStringValue()我能够获得资源价值的方法。
public enum Icon
{
/// <summary>
/// The NoruBox contains a symbol consisting of a cardboard box.
/// </summary>
[StringValue("/Noru;Component/NoruBox/Media/Box_512.png")]
Box = 0,
/// <summary>
/// The NoruBox contains a symbol consisting of a bust.
/// </summary>
[StringValue("/Noru;Component/NoruBox/Media/Person_512.png")]
Person = 1,
// More values (total of 5).
}
Run Code Online (Sandbox Code Playgroud)
另一种方法是classwith 类型的属性Icon(它将具有Name和Resource属性。这也让我可以选择添加一个GetAll()方法,该方法返回一个包含所有可用图标的列表。
public static …Run Code Online (Sandbox Code Playgroud)