從零開始搭建Wpf初學篇3-界面模塊化


前言:將控件模塊化,本章先不使用prism實現

第一步:在Views里面新建用戶控件IntroduceView,將MainWindow里面的內容拷貝過去;在ViewModels里面新建類IntroduceViewModel,將MainWindowViewModel里面的內容拷貝過去,並將IntroduceViewModel關聯到IntroduceView上。

<Grid>
    <TextBlock HorizontalAlignment="Center" Margin="0,160,0,0" Text="{Binding NoticeText}" TextWrapping="Wrap" VerticalAlignment="Top"/>
    <Button Content="點擊我" HorizontalAlignment="Left" Margin="355,236,0,0" VerticalAlignment="Top" Command="{Binding ClickCommand}"/>
</Grid>
class IntroduceViewModel : BindableBase
{
    private string _noticeText = "歡迎來到AIStudio.Wpf.Client,讓我們一起從0開始學Wpf框架搭建吧!";
    public string NoticeText
    {
        get { return _noticeText; }
        set
        {
            SetProperty(ref _noticeText, value);
        }
    }

    private ICommand _clickCommand;
    public ICommand ClickCommand
    {
        get
        {
            return this._clickCommand ?? (this._clickCommand = new DelegateCommand(() => this.Click()));
        }
    }

    private void Click()
    {
        MessageBox.Show("HelloWorld, 您點擊了一下Button按鈕");
    }
}
    
this.DataContext = new IntroduceViewModel();

第二步:MainWindow內容替換成如下:

<mah:MetroWindow  x:Class="AIStudio.Wpf.Client.MainWindow"
        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:AIStudio.Wpf.Client"
        xmlns:view="clr-namespace:AIStudio.Wpf.Client.Views"
        xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
        mc:Ignorable="d"
        Title="AIStudio.Wpf.Client" Height="450" Width="800">
  
    <Grid>
        <view:IntroduceView/>
    </Grid>
</mah:MetroWindow>

運行,將和之前的效果一樣。

第三步:添加登錄窗口,啟動的時候顯示登錄窗口,點擊登錄后切換到IntroduceView。

在Views里添加用戶控件LoginView,在ViewModels里添加LoginViewModel

<Grid x:Name="LoginGrid" HorizontalAlignment="Center" VerticalAlignment="Center">
    <Grid.RowDefinitions>
        <RowDefinition Height="30"/>
        <RowDefinition Height="30"/>
        <RowDefinition Height="30"/>
        <RowDefinition Height="30"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"></ColumnDefinition>
        <ColumnDefinition Width="150"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    
    <TextBlock Grid.Row="0" Grid.Column="0" Text="用戶名" VerticalAlignment="Center"/>

    <TextBox Grid.Row="0" Grid.Column="1" Margin="2" Text="{Binding UserName}"/>
    
    <TextBlock Grid.Row="1" Grid.Column="0" Text="密碼" VerticalAlignment="Center"/>
    <PasswordBox Grid.Row="1" Grid.Column="1" Margin="2"  core:PasswordBoxHelper.Password="{Binding Password,Mode=TwoWay}" />
    <CheckBox Grid.Row="2" Grid.ColumnSpan="2" Content="記住密碼" VerticalAlignment="Center" IsChecked="{Binding IsRmembered}" />
    <Button Grid.Row="3" Grid.ColumnSpan="2" Content="登錄" Command="{Binding LoginCommand}" IsDefault="True" />
</Grid>

注:PasswordBox的綁定需要使用附加屬性來輔助,附加屬性的實現請看我的源碼,或者百度一下。

public class LoginViewModel : BindableBase
{
    private string _userName;
    public string UserName
    {
        get { return _userName; }
        set
        {
            SetProperty(ref _userName, value);
        }
    }

    private string _password;
    public string Password
    {
        get { return _password; }
        set
        {
            SetProperty(ref _password, value);

        }
    }

    private bool _isRmembered = true;
    public bool IsRmembered
    {
        get { return _isRmembered; }
        set
        {
            SetProperty(ref _isRmembered, value);
        }
    }

    private ICommand _loginCommand;
    public ICommand LoginCommand
    {
        get
        {
            return this._loginCommand ?? (this._loginCommand = new DelegateCommand(() => this.Login()));
        }
    }

    public Action LoginSuccess;

    private void Login()
    {
        if (!string.IsNullOrEmpty(UserName)  && !string.IsNullOrEmpty(Password))
        {
            MessageBox.Show("登錄成功!");
            if (LoginSuccess != null)
            {
                LoginSuccess();                    
            }
        }
        else
        {
            MessageBox.Show("請輸入用戶名或密碼!");
        }
    }

}

可以看到里面還添加了一個LoginSuccess,用來通知MainWindowViewModel改變系統狀態。

第四步:主窗口MainWindow的控件改成ContentControl,以便可以加載不同的控件。

<Window.Resources>
    <ControlTemplate x:Key="LoginStyle" TargetType="{x:Type ContentControl}">
        <view:LoginView DataContext="{Binding LoginViewModel}"/>
    </ControlTemplate>

    <ControlTemplate x:Key="IntroduceStyle" TargetType="{x:Type ContentControl}">
        <view:IntroduceView/>
    </ControlTemplate>

    <Style x:Key="MainContentStyle" TargetType="{x:Type ContentControl}">
        <Setter Property="Template" Value="{StaticResource LoginStyle}" />
        <Style.Triggers>
            <DataTrigger Binding="{Binding Status}" Value="Introduce">
                <Setter Property="Template" Value="{StaticResource IntroduceStyle}" />
            </DataTrigger>               
        </Style.Triggers>
    </Style>
</Window.Resources>
<Grid>        
    <ContentControl  Style="{StaticResource MainContentStyle}"/>
</Grid>

注意1:可以看到Template中用DataTrigger觸發器,根據系統狀態Status,使用不同的內容模板。 注意2: <view:LoginView DataContext="{Binding LoginViewModel}"/>這里DataContext沒有使用之前的綁定方法,而是在MainWindowViewModel中new一個LoginViewModel,然后在界面上把LoginView與LoginViewModel關聯上。

第五步:MainViewModel的代碼改成如下:

class MainWindowViewModel: BindableBase
{
    private string _status = "Login";
    public string Status
    {
        get { return _status; }
        set
        {
            SetProperty(ref _status, value);
        }
    }      

    public LoginViewModel LoginViewModel { get; set; }

    public MainWindowViewModel()
    {
        LoginViewModel = new LoginViewModel();
        LoginViewModel.LoginSuccess += LoginSuccess;
    }

    private void LoginSuccess()
    {
        Status = "Introduce";
    }
}

可以看到MainWindowViewModel的子類LoginViewModel之間通信是使用LoginSuccess這個Action方法。(缺點就是不同ViewModel之間通信還很麻煩,Prism的EventAggregator很方便,后續將介紹)

源碼地址:https://gitee.com/akwkevin/aistudio.-wpf.-client.-stepby-step

另外推薦一下我的Wpf客戶端框架:https://gitee.com/akwkevin/aistudio.-wpf.-aclient


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM