在silverlight一般開發模式中,給文字框新增一些事件是輕而易舉的,然而MVVM開發模式中,想要給文字框新增一些事件並非那麼容易,因為MVVM模式中,只有ICommand介面,而且也只有Button中才有Command屬性,通過ViewModel可以將方法繫結到Button上面,卻無法繫結到文字框和其他一些控制元件。、
Behavior的出現解決了這一難題,下面就來說一下具體的實現方法:
例項一:在使用者登入視窗,使用者點選Reset按鈕後,讓使用者名稱輸入框自動獲取焦點。
首先要先將ViewModel繫結到我們的控制元件上面,我們一步一步來做,第一步先寫Model,下面是Model的程式碼:
using System; using System.Net; using System.Runtime.Serialization; using System.ComponentModel; namespace BookModel { [DataContract] public class UserModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string userName = String.Empty; private string passWord = String.Empty; [DataMember] public string UserName { get { return userName; } set { userName = value; OnPropertyChanged("UserName"); } } [DataMember] public string PassWord { get { return passWord; } set { passWord = value; OnPropertyChanged("PassWord"); } } /// <summary> /// Call the event PropertyChanged. /// </summary> /// <param name="PropertyName"></param> public void OnPropertyChanged(string PropertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(PropertyName)); } } } }
寫完了Model,下一步就是寫ViewModel了,在ViewModel中引用Model的命名控制元件,下面是ViewModel的程式碼,例子比較簡單,就不多解釋了。
using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using BookModel; using System.Windows.Browser; namespace BookViewModel { public class VM_User { /// <summary> /// In the Constructors create the instance of User. /// </summary> public VM_User() { user = new UserModel(); user.UserName = "Jack"; } public UserModel user { get; set; } public LoginCommand Login { get { return new LoginCommand(); } } public ResteCommand Reset { get { return new ResteCommand(); } } } /// <summary> /// Login Button's method /// </summary> public class LoginCommand:ICommand { public bool CanExecute(object parameter) { return true; } public void Execute(object parameter) { VM_User VMUser = parameter as VM_User; if (VMUser.user.UserName.Equals("admin") && VMUser.user.PassWord.Equals("123")) { MessageBox.Show("Login success!", "System Info", MessageBoxButton.OK); } else { MessageBox.Show("Login failed!", "System Info", MessageBoxButton.OK); } } public event EventHandler CanExecuteChanged; } /// <summary> /// Reset buttom's method /// </summary> public class ResteCommand : ICommand { public bool CanExecute(object parameter) { return true; } public void Execute(object parameter) { VM_User VMUser = parameter as VM_User; VMUser.user.UserName = ""; VMUser.user.PassWord = ""; } public event EventHandler CanExecuteChanged; } }
這裡就不連線資料庫了,那樣程式碼量太大,也不方便大家檢視。這裡只做一個簡單的驗證,至此MVVM中的M和VM就都建好了,下面寫前端的顯示層,新增兩個TextBlock和兩個TextBox,兩個按鈕。用作登入用,分別為使用者名稱,密碼,登入和重置。
下面是繫結程式碼:
<UserControl x:Class="BookLibrary.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:BookViewModel;assembly=BookViewModel" mc:Ignorable="d" d:DesignHeight="600" d:DesignWidth="1000" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"> <UserControl.Resources> <local:VM_User x:Key="User" /> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource User}}" Loaded="LayoutRoot_Loaded"> <telerik:RadBusyIndicator Name="BusyIndicator"> <Border> <Border.Background> <LinearGradientBrush EndPoint="0.5 1" StartPoint="0.5 0"> <GradientStop Color="#0369a9" Offset="0" /> <GradientStop Color="#046daf" Offset="0.5" /> <GradientStop Color="#2fa2e5" Offset="1" /> </LinearGradientBrush> </Border.Background> <Border VerticalAlignment="Center" HorizontalAlignment="Center"> <Border.Effect> <DropShadowEffect BlurRadius="10" Opacity="0.4"/> </Border.Effect> <Border.Background> <RadialGradientBrush> <GradientStop Color="#0B7AC1" Offset="0" /> <GradientStop Color="#1182c7" Offset="1" /> </RadialGradientBrush> </Border.Background> <Grid> <Grid.RowDefinitions> <RowDefinition Height="60"/> <RowDefinition Height="15"/> <RowDefinition Height="45"/> <RowDefinition Height="45"/> <RowDefinition Height="60"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="185"/> <ColumnDefinition Width="90"/> <ColumnDefinition Width="160"/> <ColumnDefinition Width="100"/> </Grid.ColumnDefinitions> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="0" Grid.Column="0" Margin="20,0,0,0" FontWeight="Bold" Text="School System |" FontSize="16" Foreground="White"/> <TextBlock Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Text="User Login" FontSize="14" Foreground="#b4e6ec"/> <Image Source="Images/LoginPicture.png" Grid.Row="1" Grid.Column="0" Grid.RowSpan="3" /> <TextBlock FontSize="14" Grid.Row="2" Grid.Column="1" Text="UserName:" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Left" /> <TextBlock FontSize="14" Grid.Row="3" Grid.Column="1" Text="PassWord:" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Left" /> <TextBox Name="txtName" Text="{Binding user.UserName,Mode=TwoWay}" HorizontalAlignment="Left" FontSize="14" Grid.Row="2" Grid.Column="2" Width="150" Height="26" /> <PasswordBox Password="{Binding user.PassWord,Mode=TwoWay}" HorizontalAlignment="Left" Grid.Row="3" Grid.Column="2" Width="150" Height="26" /> <Button Command="{Binding Login}" CommandParameter="{Binding}" HorizontalAlignment="Left" Width="80" Height="26" Grid.Row="2" Grid.Column="3" Content="Login" Click="Button_Click_1" /> <Button Command="{Binding Reset}" CommandParameter="{Binding}" HorizontalAlignment="Left" Width="80" Height="26" Grid.Row="3" Grid.Column="3" Content="Reset" Click="Button_Click" /> <CheckBox HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,10,0,0" Grid.Row="4" Grid.Column="2" Content="Save State" Foreground="White" /> </Grid> </Border> </Border> </telerik:RadBusyIndicator> </Grid> </UserControl>
這個時候,就實現登入和重置功能了,但是重置的時候使用者名稱文字框並不會獲得焦點,下面我們來講實現方法:
第一種方法:TargetedTriggerAction繫結
先寫一個類,叫做TextBoxGetFocusBahavior,程式碼如下:
using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.Windows.Interactivity; namespace BookLibrary { public class TextBoxGetFocusBahavior:TargetedTriggerAction<TextBox> { public void GotFocusAction() { } protected override void Invoke(object parameter) { TextBox targetTextBox = Target; targetTextBox.SelectAll(); } } }
然後在前臺繫結,繫結方法如下:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<TextBox Height="23" Name="textBox" HorizontalAlignment="Left" Margin="36,28,0,0" VerticalAlignment="Top" Width="198"> <i:Interaction.Triggers> <i:EventTrigger EventName="GotFocus"> <local:TextBoxGetFocusBahavior TargetName="textBox" /> </i:EventTrigger> </i:Interaction.Triggers> </TextBox>
注意我標紅的地方,就是要引入名稱空間。
第二種方法Behavior方法,和上面基本一樣,不過我感覺這種方法比較靈活,推薦使用這種方法。新加一個類,AutoSetFocusBehavior,程式碼如下:
using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.Windows.Interactivity; namespace BookLibrary { public class AutoSetFocusBehavior:Behavior<TextBox> { protected override void OnAttached() { base.OnAttached(); AssociatedObject.TextChanged += OnTextChanged; } public void OnTextChanged(object sender, EventArgs e) { if(AssociatedObject.Text.Equals("")) AssociatedObject.Focus(); } } }
這裡前端繫結方法為:
<TextBox Text="{Binding user.UserName}" x:Name="txtName" Height="27" HorizontalAlignment="Left" Margin="36,76,0,0" VerticalAlignment="Top" Width="332"> <i:Interaction.Behaviors> <local:AutoSetFocusBehavior /> </i:Interaction.Behaviors> </TextBox>
注意,同樣要引入上面的名稱空間。
其實,說了這麼多,就是給TextBox加了個OnTextChanged事件,當內容被清空時,判斷內容是否為空,為空則設定焦點。
希望這篇文章能給大家一點幫助。不足之處,還請賜教。