UWP開發之Mvvmlight實踐三:簡單MVVM實例開發(圖文詳解付代碼)

在作MVVM各類框架對比以前,我以爲有必要先本身作一個簡單的MVVM實現案例比較好,這樣就能夠看到本身實現的時候有那些不方便的地方。而各類框架又是怎麼解決咱們這些麻煩的。git

案例介紹:用戶登陸畫面,沒有輸入用戶ID數據時按鈕不可用,輸入用戶ID數據後按鈕可使用。點擊按鈕獲取用戶名信息。github

案例下載:https://github.com/NewBLife/UWP/tree/master/MvvmDemoexpress

一、建立UWP空項目框架

1

將False改爲True,這應該都懂的函數

2

二、構建項目結構佈局

按照MVVM模式思想,通常都會包含Views,ViewModels,Models,若是項目比較複雜在ViewModel和Model之間還會有Service層。測試

複雜系統狀況:this

4

三、建立Binding基類spa

MVVM核心技能之一:綁定。若是是單向顯示數據的話直接使用類屬性就能夠,若是想交互雙向綁定的實現INotifyPropertyChanged接口。其中的PropertyChanged事件會通知UI改變綁定值狀態。設計

7

代碼以下:

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace MvvmDemo.Common
{
    /// <summary>
    /// Viewmodel基類,屬性雙向綁定基礎
    /// </summary>
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// 屬性變動通知
        /// </summary>
        /// <param name="propertyName">屬性名</param>
        public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

 

四、建立Command基類

MVVM核心技能二:ICommand。這個的存在使咱們的UI邏輯能夠搬遷到其餘地方處理,給自動化單體測試與分工設計帶來了可能。按鈕的Click事件,Combox選擇,列表選擇等等均可以使用Command形式綁定到ViewModel的Command屬性作處理。

代碼以下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace MvvmDemo.Common
{
    public class DelegateCommand<T>: ICommand
    {
        /// <summary>
        /// 命令
        /// </summary>
        private Action<T> _Command;
        /// <summary>
        /// 命令能否執行判斷
        /// </summary>
        private Func<T, bool> _CanExecute;
        /// <summary>
        /// 可執行判斷結束後通知命令執行
        /// </summary>
        public event EventHandler CanExecuteChanged;

        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="command">命令</param>
        public DelegateCommand(Action<T> command):this(command,null)
        {
        }

        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="command">命令</param>
        /// <param name="canexecute">命令可執行判斷</param>
        public DelegateCommand(Action<T> command,Func<T,bool> canexecute)
        {
            if(command==null)
            {
                throw new ArgumentException("command");
            }
            _Command = command;
            _CanExecute = canexecute;
        }

        /// <summary>
        /// 命令執行判斷
        /// </summary>
        /// <param name="parameter">判斷數據</param>
        /// <returns>斷定結果(True:可執行,False:不可執行)</returns>
        public bool CanExecute(object parameter)
        {
            return _CanExecute == null ? true : _CanExecute((T)parameter);
        }

        /// <summary>
        /// 執行命令
        /// </summary>
        /// <param name="parameter">參數</param>
        public void Execute(object parameter)
        {
            _Command((T)parameter);
        }
    }
}

五、建立ViewModel

脫離UI的數據處理中心。讓咱們能夠單獨編寫它的測試程序來完成UI測試。主要目的就是將DB數據整合爲用戶想看的數據。

代碼以下:

using MvvmDemo.Common;
using MvvmDemo.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MvvmDemo.ViewModels
{
    public class MainViewModel : ViewModelBase
    {
        private string _userId;
        private string _userName;
        private DelegateCommand<string> _loginCommand;
        
        /// <summary>
        /// 用戶名
        /// </summary>
        public string UserId
        {
            get
            {
                return _userId;
            }

            set
            {
                _userId = value;
                NotifyPropertyChanged();
            }
        }
        /// <summary>
        /// 用戶名
        /// </summary>
        public string UserName
        {
            get
            {
                return _userName;
            }

            set
            {
                _userName = value;
                NotifyPropertyChanged();
            }
        }
        /// <summary>
        /// 登錄命令
        /// </summary>
        public DelegateCommand<string> LoginCommand
        {
            get
            {
                return _loginCommand
                    ??(_loginCommand=new DelegateCommand<string>(
                        s=>
                        {
                            UserName = new UserModel().GetUserName(s); 
                        },
                        s=>!string.IsNullOrEmpty(s)
                        ));
            }
        }
    }
}

六、建立View設置綁定

綁定6.0後有X:Bind,以前有Binding。x:Bind是編譯時肯定綁定對象,Binding是實行時肯定綁定對象。總得來講X:Bind的速度比Binding快,在程序運行前就能發現綁定錯誤的問題。

這裏直接就拿MainView作例子,更改下佈局

<Page
    x:Class="MvvmDemo.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MvvmDemo"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" 
          VerticalAlignment="Center"
          HorizontalAlignment="Center">
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition Height="50"/>
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <TextBlock Text="用戶ID:" Grid.Row="0" Grid.Column="0" Width="100" />
        <TextBlock Text="用戶名:" Grid.Row="1" Grid.Column="0" Width="100" />
        <TextBox x:Name="txtUserID" Grid.Row="0" Grid.Column="1" Width="150" Text="{x:Bind VM.UserId,Mode=OneWay}" />
        <TextBlock x:Name="txbUserName" Grid.Row="1" Grid.Column="1" Width="150" Text="{x:Bind VM.UserName,Mode=OneWay}"  />
        <Button x:Name="btnLogin" Content="Login" Grid.Row="2" Grid.ColumnSpan="2" Width="150" HorizontalAlignment="Center"
                Command="{x:Bind VM.LoginCommand,Mode=OneWay}"
                CommandParameter="{Binding Text,ElementName=txtUserID,Mode=OneWay}"/>
    </Grid>
</Page>

後臺添加代碼

/// <summary>
    /// 可用於自身或導航至 Frame 內部的空白頁。
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainViewModel VM =>new MainViewModel();

        public MainPage()
        {
            this.InitializeComponent();
            this.DataContext = VM;    
        }
    }

 

七、建立Model

因爲這裏沒有複雜邏輯,就不添加Service了。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MvvmDemo.Models
{
    public class UserModel
    {
        public string GetUserName(string userid)
        {
            return string.Format("取得成功:{0}",userid);
        }
    }
}

 

八、實行結果

輸入內容前按鈕自動不可用:

8

輸入內容後按鈕自動可用:

9

點擊Login按鈕:

10

九、總結

這種就是簡單的登錄實現,涉及到了MVVM的View,Viewmodel,Model,以及XBind的用法。6.0後有X:Bind,以前有Binding。x:Bind是編譯時肯定綁定對象,Binding是實行時肯定綁定對象。總得來講X:Bind的速度比Binding快,在程序運行前就能發現綁定錯誤的問題。登錄頁面的按鈕是隨着輸入自動判斷是否可用,這個就是Icommand一個方法Canexcute的做用。可見本身實現Mvvm模式也不是很難的事情,不過隨着項目的複雜加深就會有不少問題,好比Viewmode之間通訊等,這個時候纔是MVVM框架的優點所在。

相關文章
相關標籤/搜索