关于 ViewModel 对简单状态的责任的 MVVM 设计选择
MVVM design choice regarding responsibility of ViewModel for simple states
我最近开始研究 MVVM 架构模式。我已经理解了其中的大部分内容,但对于 ViewModel 应该代表 View.
承担多少责任仍然存在一些疑问
换句话说,View 应该有多笨?
例如,对于简单的状态协调,例如在用户按下 SubmitButton
后清除 TextView
。这种状态协调只需要一行代码即可使用一些流行的数据绑定框架来实现。
例如伪ReactiveCocoa:
textView.text <~ submitButton.pressed.map { _ in "" }
但是,Martin Fowler 在他的 Presentation Model、
中写道
The Presentation Model contains the logic that says that the composer field is only enabled if the check box is checked, so the when the view updates itself from the Presentation Model, the composer field control changes its enablement state
这表明即使是像在按下 Button
后清除 TextView
这样简单的逻辑也应该封装在 ViewModel
中。
这样的设计选择导致了这样的事情(同样,在伪 ReactiveCocoa 中):
// In View
viewModel.submitButtonPressed <~ submitButton.pressed
textView.text <~ viewModel.textViewText
// In ViewModel
textViewText <~ viewModel.submitButtonPressed.map { _ in "" }
虽然它会导致更好的逻辑封装,同时假设视图仅具有绑定工作(使其变得愚蠢),但它确实使代码更加冗长并导致 View
和 [= 之间更紧密的耦合16=](通过要求 ViewModel
了解 SubmitButton
)。
总的来说,我对 MVVM 模式还是陌生的,每天都在学习东西。
ViewModel应该承担多少责任?
换句话说,View
必须是完全愚蠢的并且只处理简单的绑定(将其 UI 元素连接到 ViewModel
提供的可绑定 属性)或者它是View
可以处理像上面这样相当简单的逻辑吗?
附带说明一下,在 MVVM 中 View
和 ViewModel
之间是否紧密耦合?
一般情况下,ViewModel
承担全部责任。更具体地说,在您的场景中,ViewModel
不知道 submitButton
,但是 View
会知道 ViewModel
公开了一个命令(ICommand
) 称为 SubmitCommand
,并让 submitButton
绑定到该命令。
有时,完全分离操作和相应的逻辑可能会涉及更多,例如,当特定事件的命令没有可用的绑定时。但在那些情况下,一个相当简单的附加行为(即 InvokeCommandAction
和朋友,请参阅 the documentation)可以弥合这一差距以哄骗流量,因此逻辑可以进入 ViewModel
。
很少有场景(目前想到的是 none)所以涉及到我只是跳过整个想法,并将其分开尽可能多,而不是必须在三个月后 确切 弄清楚到底发生了什么。但这种情况确实很少见。
In other words, must View be completely dumb and only handle simple binding
这很好,当视图只包含数据绑定时,但 IRL 复杂视图可以包含一些特定于视图的逻辑。例如,由于单个视图模型可以连接到多个视图,因此焦点管理是视图的特权。另一个示例是 "hide element A if element B is disabled" 或 "change color from A to B if button is checked" 等逻辑
XAML 框架提供了多种技术来使视图逻辑更加组合:命令、触发器、附加行为、值转换器。但有时您实际上需要代码隐藏。
For example, for simple state coordination like clearing TextView
after user presses SubmitButton
更清楚。 这不是视图逻辑,必须放在视图模型中:
public class ViewModel
{
private string someText;
public string SomeText
{
get { return someText; }
set
{
if (someText != value)
{
someText = value;
OnPropertyChanged();
}
}
}
private ICommand submitCommand;
public ICommand SumbitCommand
{
if (submitCommand == null)
{
submitCommand = new RelayCommand(() =>
{
// do submit
// clear text
SomeProperty = null;
});
}
return submitCommand;
}
}
XAML:
<TextBox x:Name="SomeTextBox" Text="{Binding SomeText}"/>
<Button Content="Submit" Command="{Binding SubmitCommand}">
但是这是一个视图逻辑:
public MyWindow()
{
InitializeComponent();
// SomeTextBox should have initial focus
Loaded += (sender, args) => SomeTextBox.Focus();
}
is tight coupling between View and ViewModel okay in MVVM?
理想情况下,所有组件都应松散耦合,但视图 必须 了解视图模型属性以执行数据绑定。
我最近开始研究 MVVM 架构模式。我已经理解了其中的大部分内容,但对于 ViewModel 应该代表 View.
承担多少责任仍然存在一些疑问换句话说,View 应该有多笨?
例如,对于简单的状态协调,例如在用户按下 SubmitButton
后清除 TextView
。这种状态协调只需要一行代码即可使用一些流行的数据绑定框架来实现。
例如伪ReactiveCocoa:
textView.text <~ submitButton.pressed.map { _ in "" }
但是,Martin Fowler 在他的 Presentation Model、
中写道The Presentation Model contains the logic that says that the composer field is only enabled if the check box is checked, so the when the view updates itself from the Presentation Model, the composer field control changes its enablement state
这表明即使是像在按下 Button
后清除 TextView
这样简单的逻辑也应该封装在 ViewModel
中。
这样的设计选择导致了这样的事情(同样,在伪 ReactiveCocoa 中):
// In View
viewModel.submitButtonPressed <~ submitButton.pressed
textView.text <~ viewModel.textViewText
// In ViewModel
textViewText <~ viewModel.submitButtonPressed.map { _ in "" }
虽然它会导致更好的逻辑封装,同时假设视图仅具有绑定工作(使其变得愚蠢),但它确实使代码更加冗长并导致 View
和 [= 之间更紧密的耦合16=](通过要求 ViewModel
了解 SubmitButton
)。
总的来说,我对 MVVM 模式还是陌生的,每天都在学习东西。
ViewModel应该承担多少责任?
换句话说,View
必须是完全愚蠢的并且只处理简单的绑定(将其 UI 元素连接到 ViewModel
提供的可绑定 属性)或者它是View
可以处理像上面这样相当简单的逻辑吗?
附带说明一下,在 MVVM 中 View
和 ViewModel
之间是否紧密耦合?
一般情况下,ViewModel
承担全部责任。更具体地说,在您的场景中,ViewModel
不知道 submitButton
,但是 View
会知道 ViewModel
公开了一个命令(ICommand
) 称为 SubmitCommand
,并让 submitButton
绑定到该命令。
有时,完全分离操作和相应的逻辑可能会涉及更多,例如,当特定事件的命令没有可用的绑定时。但在那些情况下,一个相当简单的附加行为(即 InvokeCommandAction
和朋友,请参阅 the documentation)可以弥合这一差距以哄骗流量,因此逻辑可以进入 ViewModel
。
很少有场景(目前想到的是 none)所以涉及到我只是跳过整个想法,并将其分开尽可能多,而不是必须在三个月后 确切 弄清楚到底发生了什么。但这种情况确实很少见。
In other words, must View be completely dumb and only handle simple binding
这很好,当视图只包含数据绑定时,但 IRL 复杂视图可以包含一些特定于视图的逻辑。例如,由于单个视图模型可以连接到多个视图,因此焦点管理是视图的特权。另一个示例是 "hide element A if element B is disabled" 或 "change color from A to B if button is checked" 等逻辑
XAML 框架提供了多种技术来使视图逻辑更加组合:命令、触发器、附加行为、值转换器。但有时您实际上需要代码隐藏。
For example, for simple state coordination like clearing TextView after user presses SubmitButton
更清楚。 这不是视图逻辑,必须放在视图模型中:
public class ViewModel
{
private string someText;
public string SomeText
{
get { return someText; }
set
{
if (someText != value)
{
someText = value;
OnPropertyChanged();
}
}
}
private ICommand submitCommand;
public ICommand SumbitCommand
{
if (submitCommand == null)
{
submitCommand = new RelayCommand(() =>
{
// do submit
// clear text
SomeProperty = null;
});
}
return submitCommand;
}
}
XAML:
<TextBox x:Name="SomeTextBox" Text="{Binding SomeText}"/>
<Button Content="Submit" Command="{Binding SubmitCommand}">
但是这是一个视图逻辑:
public MyWindow()
{
InitializeComponent();
// SomeTextBox should have initial focus
Loaded += (sender, args) => SomeTextBox.Focus();
}
is tight coupling between View and ViewModel okay in MVVM?
理想情况下,所有组件都应松散耦合,但视图 必须 了解视图模型属性以执行数据绑定。