阅读this article后,我的PersonViewModel
课程中包含以下代码:
public Jurisdiction CountryResidence
{
get
{
return Model.CountryResidence;
}
set
{
if (Model.CountryResidence == value)
return;
else
{
Model.CountryResidence = value;
base.OnPropertyChanged("CountryResidence");
}
}
}
public Jurisdiction CountryBirth
{
get
{
return Model.CountryBirth;
}
set
{
if (Model.CountryBirth == value)
return;
else
{
Model.CountryBirth = value;
base.OnPropertyChanged("CountryBirth");
}
}
}
我还有CountryDomiciled
,CountryPassport
和LegalJurisdiction
,所有格式都相同。同样,我有很多String
属性,所有属性都共享它们的格式。
这导致了许多相同的代码!但是,我无法弄清楚如何使这更简洁。
有没有更好的方法来生成这些属性以保持强类型?
答案 0 :(得分:10)
我在Visual Studio中使用了代码段,它为我生成了支持存储和事件提升的属性。只需创建名称为propchanged
的xml文件(或其他名称,如果您愿意)和以下内容:
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>propchanged</Title>
<Shortcut>propchanged</Shortcut>
<Description>Code snippet for property (with call to OnPropertyChanged) and backing field</Description>
<Author>lazyberezovsky</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>Property type</ToolTip>
<Default>string</Default>
</Literal>
<Literal>
<ID>property</ID>
<ToolTip>Property name</ToolTip>
<Default>MyProperty</Default>
</Literal>
<Literal>
<ID>field</ID>
<ToolTip>The variable backing this property</ToolTip>
<Default>myVar</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[private $type$ $field$;
public $type$ $property$
{
get { return $field$;}
set
{
if ($field$ == value)
return;
$field$ = value;
OnPropertyChanged("$property$");
}
}
$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
并将其放入文件夹C:\Users\YourName\Documents\Visual Studio 2010\Code Snippets\Visual C#\My Code Snippets\
。
接下来,我从一些基础ViewModel继承我的ViewModel,它实现INotifyPropertyChanged
inteface并提供受保护的方法OnPropertyChanged
来生成`PropertyChanged'事件。
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName);
}
}
现在,当您在Visual Studio中键入propchanged
时,它会询问您的属性类型和名称,并为您生成代码。
public class PersonViewModel : ViewModel
{
// type here 'propchanged' (or other shortcut assigned for snippet)
}
更新:
另一种选择是通过像PostSharp这样的AOP框架生成代码。在这种情况下,代码将在编译期间生成并添加(因此您的类将保持干净)。 Here是通过PostSharp属性实现更改INotifyProperty的示例:
[Notify]
public class PersonViewModel
{
public Jurisdiction CountryResidence { get; set; }
public Jurisdiction CountryBirth { get; set; }
}
答案 1 :(得分:4)
更新:NotifyPropertyWeaver已弃用,并且其生命周期为PropertyChanged.Fody。这是解决此问题的绝对超酷方式。它只是一个编译时解决方案。
这可以节省代码和麻烦:NotifyPropertyWeaver
使用上述内容,您可以在没有任何INotifyPropertyChanged
相关代码的情况下实现您的属性,并且构建步骤将为您处理连接。
这是一个简单的项目包括(也可以通过Nuget获得),它会自动将OnPropertyChanged
回调注入到实现INotifyPropertyChanged
的任何类的属性中。它在编译时执行(因此没有运行时命中),并且您的代码可以只具有自动实现的属性(在您的情况下,您使用单独的后备对象除外)。
它甚至包括值相等检查,因此它涵盖了完整的逻辑。我没有使用手动实现的属性对其进行测试,但值得一试。
编辑:我现在已经对它进行了测试,并且工作正常:手动实现的属性将“正常工作。”
答案 2 :(得分:2)
不是你真正想要的东西,但是除了你可以通过反转你的逻辑测试来保存每个属性两行:
public Jurisdiction CountryResidence
{
get
{
return Model.CountryResidence;
}
set
{
if (Model.CountryResidence != value)
{
Model.CountryResidence = value;
base.OnPropertyChanged("CountryResidence");
}
}
}
答案 3 :(得分:1)
我不知道任何内置方式,但您可以录制一个将为您生成代码的宏。我发现最简单的方法是开始录制一个宏,然后仅使用键盘创建你想要的任何内容(你可以找到一个方便的键盘快捷键列表here)
例如,我有一个生成属性的公共版本,因此我必须输入private string _someValue;
并点击我的宏,它将生成公共属性以及属性更改通知。< / p>
那就是说,请记住,为了简单和方便起见,在MVVM中将整个模型暴露给View是完全有效的。因此,您只需为Model对象创建一个属性,而不是单独公开每个Model的属性。
public Model SomeModel
{
get
{
return Model;
}
set
{
if (Model == value)
return;
else
{
Model= value;
base.OnPropertyChanged("SomeModel");
}
}
}
并绑定到模型的属性,如下所示:
<TextBox Text="{Binding SomeModel.SomeProperty}" />
答案 4 :(得分:1)
请尝试XAML PowerToys快速生成ViewModels;
答案 5 :(得分:1)
要获取属性名称的“强类型”引用(这是启用重构所必需的), 你可以使用表达式。将以下方法放在viewmodel的基类中:
protected void RaisePropertyChanged<T>(Expression<Func<T>> property)
{
var handler = PropertyChanged;
if (handler == null) return;
var propertyName = NotifyPropertyChangedHelper.GetPropertyNameFromExpression(property);
handler(sender, new PropertyChangedEventArgs(propertyName));
}
在您的视图模型中,您将能够执行以下操作:
public Jurisdiction CountryResidence
{
get { return Model.CountryResidence; }
set
{
if (Model.CountryResidence == value)
return;
Model.CountryResidence = value;
OnPropertyChanged(() => CountryResidence);
}
}
现在,自动引用重构属性名称,因为引用是针对实际属性的。
这解决了硬编码属性名称的痛点,尽管它仍然需要4-5行样板代码。面向方面的方法(如notifypropertyweaver和PostSharp)确实会删除视图模型中的所有手动编码。
答案 6 :(得分:0)
您是否尝试过使用prop
或propfull
等Visual Studio代码段?只需键入它并按Tab键两次。问题是propfull
代码段不会引发 PropertyChanged 事件。
但实际上应该有第三方片段用于此类任务。这是我找到的:property snippet with INPC
答案 7 :(得分:0)