wpf 入门demo(一)

创建

新建项目

打开Visual Studio 2019,选择“创建新项目--》WPF应用程序”。如下图。

138

139

生成的目录

创建成功后自动生成的目录如下

140

  • App.xaml : 设置应用程序的起始文件与资源
  • App.xaml .csApp.xaml 的后台文件,继承自System.Windows.Application,用于处理整个wpf应用程序相关
  • MainWindow.xaml: wpf应用程序界面xaml设计文件
  • MainWindow.xaml.cs: MainWindow.xaml文件的后台 代码继承自System.Windows.Window

布局

修改MainWindow.xaml

<Window
    x:Class="wpf_basic.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:local="clr-namespace:wpf_basic"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
            <TextBlock
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Text="账号:" />
            <TextBox
                Name="TxtA"
                Width="300"
                Height="30" />
        </StackPanel>
        <StackPanel
            Grid.Row="1"
            HorizontalAlignment="Center"
            Orientation="Horizontal">
            <TextBlock
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Text="密码:" />
            <TextBox
                Name="TxtP"
                Width="300"
                Height="30" />
        </StackPanel>
        <Button
            Name="BtnLogin"
            Grid.Row="2"
            Width="200"
            Height="30"
            Content="Login" />
    </Grid>
</Window>

  • ColumnDefinitions 定义多少列,RowDefinitions定义多少行。

  • Grid.Row="行编号",若行编号为0,则可忽略,列同样如此

  • StackPanel可以把内部元素再纵向或横向紧凑排列,形成栈式布局。

效果

141

可以看到我们定义了三行,TextBlock和TextBox这两个控件采用了横向紧凑排列并居中。

控件

添加按钮点击事件

在MainWindow.xaml的Button中添加点击属性

        <Button
            Name="BtnLogin"
            Grid.Row="2"
            Width="200"
            Height="30"
            Click="BtnLogin_Click"
            Content="Login" />

在 MainWindow.xaml中添加BtnLogin_Click事件

        private void BtnLogin_Click(object sender, RoutedEventArgs e)
        {
            string a = TxtA.Text;
            string p = TxtP.Text;

            if (a == "xzw" && p == "123456")
            {
                MessageBox.Show("登录成功!");
            }
            else
            {
                MessageBox.Show("登录失败!");
            }
        }

运行之后点击按钮就会显示是否登入成功

绑定

绑定主要分为:1. 绑定目标 2. 绑定属性 3. 绑定模式 4. 绑定数据源 5. 关联资源。

  • 绑定目标: 就是你要操作绑定的控件。例如:Button,TextBox。

  • 绑定属性(依赖项属性): <TextBox Width="200" Height="25" Text="{Bingding Name}"></TextBox> Text就是绑定属性, Bingding 是绑定关键字,而后面的Name就是你要绑定的数据源的变量名。

  • 绑定模式:

    • TwoWay 无论是目标属性还是源属性,只要发生了更改,TwoWay 就会更新目标属性或源属性。
    • OneWay 仅当源属性发生更改时更新目标属性。
    • OneTime 仅当应用程序启动时或 DataContext 进行更改时更新目标属性。
    • OneWayToSource 在目标属性更改时更新源属性。
    • Default:模式根据实际情况来定,如果是可编辑的就是TwoWay,只读的就是OneWay.
  • 绑定数据源:一般来说可以是单个变量(int , double,string)、也可以是一个数据集(List)。

  • 关联资源(DataContext ): 在每一个窗体中,都有一个DataContext ,它是一个object类型主要用来存储绑定资源。

修改MainWindow.xaml

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
            <TextBlock
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Text="账号:" />
            <TextBox
                Name="TxtA"
                Width="300"
                Height="30"
                Text="{Binding Account,UpdateSourceTrigger=PropertyChanged}" />
        </StackPanel>
        <StackPanel
            Grid.Row="1"
            HorizontalAlignment="Center"
            Orientation="Horizontal">
            <TextBlock
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Text="密码:" />
            <TextBox
                Name="TxtP"
                Width="300"
                Height="30"
                Text="{Binding PassWrold, Mode=TwoWay}" />
        </StackPanel>
        <ComboBox
            Grid.Row="2"
            Width="200"
            Height="25"
            ItemsSource="{Binding LoginTypes}" />
        <Button
            Name="BtnLogin"
            Grid.Row="3"
            Width="200"
            Height="30"
            Click="BtnLogin_Click"
            Content="Login" />
    </Grid>

新建LoginModel.cs

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

namespace wpf_basic
{
    class LoginModel
    {
        private string _account;
        public string Account
        {
            get { return _account; }
            set
            {
                _account = value;
            }
        }

        private string _passwrold;
        public string PassWrold
        {
            get { return _passwrold; }
            set
            {
                _passwrold = value;
            }
        }

        private List<string> _loginTypes;
        public List<string> LoginTypes
        {
            get { return _loginTypes; }
            set { _loginTypes = value; }
        }

        public LoginModel()
        {
            Account = "root";
            LoginTypes = new List<string>();
            LoginTypes.Add("手机号登录");
            LoginTypes.Add("账号密码登录");
            LoginTypes.Add("二维码登录");
        }
    }
}
  • UpdateSourceTrigger的默认值是Default,其他值有PropertyChangedLostFocusExplicit

    • Explicit,源不会更新除非你手动来操作。
    • LostFocus,对于Text绑定来说其实就是一个默认值。也就是说一旦目标控件失去焦点,源就会被更新。
    • PropertyChanged,一旦绑定的属性值改变,源会立即更新。
  • 账号的TextBox 绑定了Account,并且一旦TextBox控件里的值改变,LoginModel.cs里的Account属性的值就会改变。

  • 密码的TextBox绑定了cs文件中的PassWrold。

  • ComboBox绑定的是一个数据集。

修改MainWindow.xaml.cs

添加: DataContext = new LoginModel();

所有基本绑定都在UI对象的数据层(DataContext)中寻找它们的值。

namespace wpf_basic
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new LoginModel();
        }

        private void BtnLogin_Click(object sender, RoutedEventArgs e)
        {
            string a = TxtA.Text;
            string p = TxtP.Text;

            if (a == "xzw" && p == "123456")
            {
                MessageBox.Show("登录成功!");
            }
            else
            {
                MessageBox.Show("登录失败!");
            }
        }
    }
}

效果

142

命令

上面处理按钮事件,前端代码会和后端代码耦合在一起。

  • 一般来说,事件与命令几乎相同,只是处理用户交互的不同模式.。
  • 命令解耦合一开始比较复杂,但是项目复杂之后比事件好扩展。

ICommand

Command是所有命令的接口,它主要完成两件事情,这个命令能否被执行,以及执行命令。

public interface ICommand{
    void Execute(object parameter);
    bool CanExecute(object parameter);
    event EventHandler CanExecuteChanged;
}
  • Execute方法将包含引用程序任务逻辑。
  • Execute和CanExecute方法都接受一个附加的对象参数,可使用该对象传递所需的任何附加信息。
  • CanExecuteChanged,当命令状态改变是引发该事件。对于使用命令的任何控件,这是指示信号,表示他们应当调用CanExecute方法检查命令的状态。通过使用该事件,当命令可用时,命令源(如button)可自动启用自身;当命令不可用时,禁用自身。

创建wpf_common模块

  • 添加新项目 -》 WPF应用程序,新建wpf_common模块,去掉里面的StartupUri并新建MyCommand.cs
  • 为什么选择WPF应用程序而不用C# 类库.是因为选用C#类库讲图片设为资源时,解决方案栏会不显示图片以及其目录。
using System;
using System.Diagnostics;
using System.Windows.Input;

namespace wpf_common
{
    public class MyCommand : ICommand
    {
        #region 字段
        readonly Func<Boolean> _canExecute;

        readonly Action _execute;
        #endregion

        #region 构造函数
        // 下面两个是构造函数
        public MyCommand(Action execute)
            : this(execute, null)
        {

        }
        public MyCommand(Action execute, Func<Boolean> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }
        #endregion

        #region ICommand的成员
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (_canExecute != null)
                    CommandManager.RequerySuggested += value;
            }

            remove
            {
                if (_canExecute != null)
                    CommandManager.RequerySuggested -= value;
            }
        }

        [DebuggerStepThrough]

        public Boolean CanExecute(Object parameter)
        {
            return _canExecute == null ? true : _canExecute();
        }

        public void Execute(Object parameter)
        {
            _execute();
        }
        #endregion

    }
    public class MyCommand<T> : ICommand {
        readonly Action<T> _execute = null;
        readonly Predicate<T> _canExecute = null;

        public MyCommand(Action<T> execute)
         : this(execute, null)
        {
        }
        /// <summary>
        /// Creates a new command.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        /// <param name="canExecute">The execution status logic.</param>
        public MyCommand(Action<T> execute, Predicate<T> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }



        public bool CanExecute(object parameter)
        {
            return _canExecute == null || _canExecute((T)parameter);
        }

        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (_canExecute != null)
                    CommandManager.RequerySuggested += value;
            }
            remove
            {
                if (_canExecute != null)
                    CommandManager.RequerySuggested -= value;
            }
        }

        public void Execute(object parameter)
        {
            _execute((T)parameter);
        }
    }

}
  • 上面实现了两个ICommand,一个不传参数类型一个传参数类型。

添加依赖项

右击wpf_basic的依赖项,添加wpf_common项目引用

143

修改LoginModel.cs

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

namespace wpf_basic
{
    class LoginModel
    {
        private string _account;

        public string Account
        {
            get { return _account; }
            set
            {
                _account = value;
            }
        }

        private string _passwrold;

        public string PassWrold
        {
            get { return _passwrold; }
            set
            {
                _passwrold = value;
            }
        }

        private List<string> _loginTypes;

        public List<string> LoginTypes
        {
            get { return _loginTypes; }
            set { _loginTypes = value; }
        }


        public ICommand LoingCommand { get; set; }
        public ICommand CancelRemberCommand { get; set; }




        public LoginModel()
        {
            LoingCommand = new MyCommand(LoginAction);
            CancelRemberCommand = new MyCommand<bool>(CancelAction);
            Account = "root";
            LoginTypes = new List<string>();
            LoginTypes.Add("手机号登录");
            LoginTypes.Add("账号密码登录");
            LoginTypes.Add("二维码登录");
        }

        private void CancelAction(bool obj)
        {
            MessageBox.Show($"check status { obj }");
        }

        private void LoginAction()
        {
            if (Account == "root" && PassWrold == "123")
            {
                MessageBox.Show("登录成功!");
            }
            else
            {
                MessageBox.Show("登录失败!");
            }
        }
    }
}

  • 在构造函数中添加了LoingCommand , CancelRemberCommand两个命令,这两个命令分别绑定LoginAction 和 CancelAction这两个动作。

修改MainWindow.xaml

<Window
    x:Class="wpf_basic.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:local="clr-namespace:wpf_basic"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
            <TextBlock
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Text="账号:" />
            <TextBox
                Name="TxtA"
                Width="300"
                Height="30"
                Text="{Binding Account, UpdateSourceTrigger=PropertyChanged}" />
        </StackPanel>
        <StackPanel
            Grid.Row="1"
            HorizontalAlignment="Center"
            Orientation="Horizontal">
            <TextBlock
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Text="密码:" />
            <TextBox
                Name="TxtP"
                Width="300"
                Height="30"
                Text="{Binding PassWrold, Mode=TwoWay}" />
        </StackPanel>
        <StackPanel
            Grid.Row="2"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Orientation="Horizontal">
            <ComboBox
                Width="200"
                Height="25"
                ItemsSource="{Binding LoginTypes}" />
            <CheckBox
                x:Name="ChkboxPwd"
                Margin="5"
                Content="是否记住密码?" />
        </StackPanel>
        <StackPanel
            Grid.Row="3"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Orientation="Horizontal">
            <Button
                Name="BtnLogin"
                Width="200"
                Height="30"
                Margin="3"
                Command="{Binding LoingCommand}"
                Content="Login" />
            <Button
                Width="200"
                Height="30"
                Margin="3"
                Command="{Binding CancelRemberCommand}"
                CommandParameter="{Binding ElementName=ChkboxPwd, Path=IsChecked}"
                Content="check" />
        </StackPanel>
    </Grid>
</Window>

  • Login按钮绑定了LoingCommand 命令,check绑定了CancelRemberCommand命令,并且添加命令参数CommandParameter

修改MainWindow.xaml.cs

因为采用命令的方式而不采用事件,所以注释掉函数BtnLogin_Click

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace wpf_basic
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new LoginModel();
        }

        /*private void BtnLogin_Click(object sender, RoutedEventArgs e)
        {
            string a = TxtA.Text;
            string p = TxtP.Text;

            if (a == "xzw" && p == "123456")
            {
                MessageBox.Show("登录成功!");
            }
            else
            {
                MessageBox.Show("登录失败!");
            }
        }*/
    }
}

测试

144

点击check按钮,如果勾选了记住密码就返回check status True,否则返回check status False

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×