将视图模型从 C# 转换为 F#
Convert viewmodel from C# to F#
F# 中的以下 ViewModel 是什么样子的?
namespace MVVMExample
{
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
RaisePropertyChanged("FirstName");
}
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
RaisePropertyChanged("LastName");
}
}
public string GetFullName()
{
return string.Format("{0} {1}", FirstName, LastName);
}
protected void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
注意:
我是 F# 的新手,真的很想了解如何从 C# 简化代码。
我更喜欢使用基础 ViewModel
来继承和公开使用引号的接口,因此我不需要手动提供字符串 属性 名称(这对代码不友好重构)。
请注意,根据已接受的问题答案:Is it possible to use CallerMemberNameAttribute in f# F# 不支持 [<CallerMemberName>]
属性,因此我使用引号来执行此操作。
如果您在 C# 中定义基础 ViewModel
class 并从 F# 中的 class 继承,您仍然可以获得 [<CallerMemberName>]
的好处。不过,出于此答案的目的,我将向您展示一个纯 F# 解决方案。
type ViewModel () =
let propertyChanged =
Event<PropertyChangedEventHandler,PropertyChangedEventArgs>()
let getPropertyName = function
| PropertyGet(_,pi,_) -> pi.Name
| _ -> invalidOp "Expecting property getter expression"
interface INotifyPropertyChanged with
[<CLIEvent>]
member this.PropertyChanged = propertyChanged.Publish
member private this.NotifyPropertyChanged propertyName =
propertyChanged.Trigger(this,PropertyChangedEventArgs(propertyName))
member this.NotifyPropertyChanged quotation =
quotation |> getPropertyName |> this.NotifyPropertyChanged
然后从中得出您的特定 ViewModel
。
type NimrodViewModel() =
inherit ViewModel()
let mutable firstName = ""
let mutable lastName = ""
member this.FirstName
with get() = firstName
and set(value) =
firstName <- value
base.notifyPropertyChanged(<@ this.FirstName @>)
member this.LastName
with get() = lastName
and set(value) =
lastName <- value
base.notifyPropertyChanged(<@ this.LastName @>)
member this.GetFullName() =
sprintf "%s %s" (this.FirstName) (this.LastName)
使用FSharp.Desktop.UI,它看起来像这样:
[<AbstractClass>]
type ViewModel() =
inherit Model()
abstract FirstName: string with get, set
abstract LastName: string with get, set
[<DerivedProperty>]
member this.FullName = sprintf "%s %s" this.FirstName this.LastName
然后 let model: MyViewModel = ViewModel.Create()
将创建 ViewModel 的实例。
通过使 FullName
成为 属性 并用 DerivedProperty
属性装饰它,任何绑定到它的控件都会在它依赖的任何属性被更改时自动获得更改通知改变了。
我知道您没有要求使用库的示例,但我想展示在使用正确的社区库时 F# 可以多么简洁。
F# 中的以下 ViewModel 是什么样子的?
namespace MVVMExample
{
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
RaisePropertyChanged("FirstName");
}
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
RaisePropertyChanged("LastName");
}
}
public string GetFullName()
{
return string.Format("{0} {1}", FirstName, LastName);
}
protected void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
注意:
我是 F# 的新手,真的很想了解如何从 C# 简化代码。
我更喜欢使用基础 ViewModel
来继承和公开使用引号的接口,因此我不需要手动提供字符串 属性 名称(这对代码不友好重构)。
请注意,根据已接受的问题答案:Is it possible to use CallerMemberNameAttribute in f# F# 不支持 [<CallerMemberName>]
属性,因此我使用引号来执行此操作。
如果您在 C# 中定义基础 ViewModel
class 并从 F# 中的 class 继承,您仍然可以获得 [<CallerMemberName>]
的好处。不过,出于此答案的目的,我将向您展示一个纯 F# 解决方案。
type ViewModel () =
let propertyChanged =
Event<PropertyChangedEventHandler,PropertyChangedEventArgs>()
let getPropertyName = function
| PropertyGet(_,pi,_) -> pi.Name
| _ -> invalidOp "Expecting property getter expression"
interface INotifyPropertyChanged with
[<CLIEvent>]
member this.PropertyChanged = propertyChanged.Publish
member private this.NotifyPropertyChanged propertyName =
propertyChanged.Trigger(this,PropertyChangedEventArgs(propertyName))
member this.NotifyPropertyChanged quotation =
quotation |> getPropertyName |> this.NotifyPropertyChanged
然后从中得出您的特定 ViewModel
。
type NimrodViewModel() =
inherit ViewModel()
let mutable firstName = ""
let mutable lastName = ""
member this.FirstName
with get() = firstName
and set(value) =
firstName <- value
base.notifyPropertyChanged(<@ this.FirstName @>)
member this.LastName
with get() = lastName
and set(value) =
lastName <- value
base.notifyPropertyChanged(<@ this.LastName @>)
member this.GetFullName() =
sprintf "%s %s" (this.FirstName) (this.LastName)
使用FSharp.Desktop.UI,它看起来像这样:
[<AbstractClass>]
type ViewModel() =
inherit Model()
abstract FirstName: string with get, set
abstract LastName: string with get, set
[<DerivedProperty>]
member this.FullName = sprintf "%s %s" this.FirstName this.LastName
然后 let model: MyViewModel = ViewModel.Create()
将创建 ViewModel 的实例。
通过使 FullName
成为 属性 并用 DerivedProperty
属性装饰它,任何绑定到它的控件都会在它依赖的任何属性被更改时自动获得更改通知改变了。
我知道您没有要求使用库的示例,但我想展示在使用正确的社区库时 F# 可以多么简洁。