从一个登录页面浅淡MVVM(三)

在 ViewModels 中增加一个 ViewModelCommand ,通过 Action<Object> 执行实际的方法。

 

ViewModelCommand.cs
 
   
/// <summary>
/// 使用 Action <Object> 作为通用的 Command,如果要使用 Action <T> 的其他形式,则要创建新的类型。
/// 使用 struct 从 Heap 中进行存储,性能更高
/// </summary>
public struct ViewModelCommand : ICommand
{
private Action < Object > action;
public Action < Object > ViewModelAction
{
get { return action; }
set { action = value; }
}

public ViewModelCommand(Action < Object > act)
{
action
= act;
}

public bool CanExecute(Object parameter)
{
return true ;
}
public void Execute(Object parameter)
{
this .ViewModelAction(parameter);
}
public event EventHandler CanExecuteChanged
{
add { }
remove { }
}
}

 

 

PS:日前,在看有关 Object Value  的用法时,提到了 struct ,struct 是存储在 Heap 上,而引用类型是存储在

Stack 上的,在内存分配及垃圾回收等方面 struct 的性能更高,所以这里把 ViewModelCommand 改为 struct。

 

在 LoginViewModel.cs 中增加两个Command,分别用于前台 UI 的两个 Button 的 Command 绑定。

 

LoginViewModel.cs
 
   
public ViewModelCommand GenerateValidationCodeCommand { get ; private set ; }
public ViewModelCommand LoginCommand { get ; private set ; }

public LoginViewModel()
{
this .Data = new User();
this .GenerateValidationCodeCommand = new ViewModelCommand((Object parameter) =>
{
this .GenerateValidationCodeAsync();
});
this .LoginCommand = new ViewModelCommand((Object parameter) =>
{
if ( this .Validate())
{
this .LoginAsync();
}
});
}

同时,尝试将要执行 Validation 的 UI 引用移入 ViewModel 中

 

LoginViewModel.cs
 
   
/// <summary>
/// 用于控制UI的ValidationSummary
/// </summary>
public ValidationSummary ValidationSummary { get ; set ; }
/// <summary>
/// 用于控制UI的控件的校验
/// </summary>
public UIElementCollection ValidationUICollection { get ; set ; }

/// <summary>
/// 针对 ValidationSummary 和 ValidationUICollection 进行校验
/// </summary>
/// <returns></returns>
public bool Validate()
{
if ( this .ValidationSummary != null && this .ValidationSummary.HasErrors)
{
return false ;
}
else if ( this .ValidationUICollection != null )
{
// 扩展方法,校验各个控件的数据绑定
this .ValidationUICollection.ValidateSource();
if ( this .ValidationSummary != null && this .ValidationSummary.HasErrors)
{
return false ;
}
}
return true ;
}

 

这样,View 就更简单了,在 Xaml 中变为

 

 
  
< Button Content = " 换一个 " Grid.Column = " 3 " Grid.Row = " 2 " Height = " 23 " Margin = " 8 "
Name
= " btnChangeValidationCode " Width = " 75 "
Command
= " {Binding GenerateValidationCodeCommand} " />

< Button Content = " 登录 " Grid.Row = " 3 " Grid.ColumnSpan = " 4 " Margin = " 8 " Name = " btnLogin "
Command
= " {Binding LoginCommand} " />

 

LoginPage.cs 变为

 

LoginPage.cs
 
   
public partial class LoginPage : Page
{
LoginViewModel loginVM;

public LoginPage()
{
InitializeComponent();
this .loginVM = new LoginViewModel()
{
ValidationSummary
= this .validationSummary1,
ValidationUICollection
= this .LayoutRoot.Children
};
this .loginVM.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(loginVM_PropertyChanged);
this .Loaded += new RoutedEventHandler(LoginPage_Loaded);
}

void loginVM_PropertyChanged( object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == " IsDone " )
{
if ( this .loginVM.IsDone)
{
// 登录成功,执行跳转
}
}
else if (e.PropertyName == " Message " )
{
// 可以在 UI 上将 Message 也和 TextBlock 等进行绑定,以显示消息
MessageBox.Show( this .loginVM.Message);
}
}

void LoginPage_Loaded( object sender, RoutedEventArgs e)
{
this .loginVM.GenerateValidationCodeAsync();
this .DataContext = this .loginVM;
}

}

 

使用 MVVM ,好处很明显,LoginPage.cs 中的代码几乎减少至只剩下 实例化 ViewModel 和为 DataContext

赋值的语句了,代码人员和设计人员可以分开工作。

 

但是,View 和 ViewModel 之间如何依赖?

显然 View 是依赖于 ViewModel 的,但是 ViewModel 该不该依赖于 View ,也就是说 LoginPageViewModel 该不该

拥有一个指向 LoginPage 实例的属性或字段?

 

在 Silverlight Templated Control 中,代码和Xaml是分离的,代码和Xaml通过约定的 TemplatePart 的名字各自

进行编码,而代码在运行时通过 GetTemplateChild(name) 取得控件的实例,

这种分离,允许我们把 Silverlight Templated Control定义在最低层次的类库,而在运行时于最高层的 App 应用程序中

重新为 Silverlight Templated Control 指定外观,那么,在 MVVM 中,View 和 ViewModel 是否也能这样分离呢?

 

如果要实现这种分离,那么 ViewModel 便不可能依赖于 View ,最多只能是定义一些 interface,View 从 interface 中

派生,而 ViewModel 依赖于 interface。

联想起 ASP.NET MVC 2,每一个页面对应一个 Model,这个 Model 其实就相当于是 ViewModel,依稀记得 MVC 2 中

ViewModel 是不会关注 View 的。

 

嗯,存疑,先至此,欢迎各位进行指正和讨论。

转载于:https://www.cnblogs.com/Sunpire/archive/2010/12/25/1916943.html

创建一个基于MVVM设计模式的新布局文件及其关联的ViewModel和Activity通常涉及以下步骤: 1. **布局文件 (XML)**: - 新建一个XML文件,例如`activity_main.xml`,在Android Studio里可以在"res/layout"目录下右键选择"New > Layout resource file"。在此文件中,你可以设计UI组件,如TextView、Button等,并按照需要组织它们。 2. **ViewModel**: - 创建一个新的Kotlin或Java类,命名它通常以`YourActivityNameViewModel`结尾,比如`MainActivityViewModel`。这个类应该继承自`ViewModel`(如果使用的是Android Architecture Components库),并可以包含数据属性和观察者模式来处理业务逻辑和数据交互。 ```java // MainActivityViewModel.java class MainActivityViewModel extends ViewModel { private MutableLiveData<String> message = new MutableLiveData<>(); public void setMessage(String text) { message.setValue(text); } public LiveData<String> getMessage() { return message; } } ``` 3. **Activity/Fragment**: - 创建一个新的Activity(如果是Activity)或Fragment(如果是片段),例如`MainActivity.kt`或`MainActivityFragment.kt`。在这个文件中,首先设置内容提供者为你的ViewModel实例,然后通过LiveData或者其他通知机制监听数据变化。 ```kotlin // MainActivity.kt class MainActivity : AppCompatActivity() { private lateinit var viewModel: MainActivityViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java) // ... 在这里绑定UI元素到ViewModel的方法,例如: viewModel.getMessage().observe(this, Observer { message -> findViewById<TextView>(R.id.message_text_view).text = message }) } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值