WPF原理

发布时间 2023-11-10 15:28:11作者: 茜茜87

1.Xaml标记实现和代码隐藏

<Window x:Class="WpfApp1.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:WpfApp1" 
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Slider HorizontalAlignment="Left" Margin="106,38,0,0" VerticalAlignment="Top" Width="621" Value="{Binding Input1}"/>
        <Slider HorizontalAlignment="Left" Margin="106,83,0,0" VerticalAlignment="Top" Width="621" Value="{Binding Input2}"/>
        <Slider HorizontalAlignment="Left" Margin="106,132,0,0" VerticalAlignment="Top" Width="621" Value="{Binding Result}"/>
        <Button Content="Button" HorizontalAlignment="Left" Margin="355,200,0,0" VerticalAlignment="Top" Width="99" Height="29" Command="{Binding AddCommand}"/>
    </Grid>
</Window>

更新的标记定义 xmlns:x 命名空间,并将其映射到为代码隐藏类型添加支持的架构。 x:Class 特性用于将代码隐藏类与此特定 XAML 标记相关联。 考虑此特性在 <Window> 元素上声明,代码隐藏类必须从 Window 类继承。

namespace WpfApp1
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            // InitializeComponent call is required to merge the UI
            // that is defined in markup with this class, including  
            // setting properties and registering event handlers           
            InitializeComponent();

            this.DataContext = new MainWindowViewModel();
        }
    }
}

从代码隐藏类的构造函数调用 InitializeComponent,以将标记中定义的 UI 与代码隐藏类合并在一起。x:Class 和 InitializeComponent 的组合可确保在创建实现时正确地对其进行初始化。

 

若要使 XAML 标记文件和代码隐藏文件配合工作,需要满足以下要求:

  • 在标记中,Window 元素必须包含 x:Class 属性。 生成应用程序时,标记文件中存在 x:Class 会使 Microsoft 生成引擎 (MSBuild) 生成派生自 Window 的 partial 类,其名称由 x:Class 属性指定。 这要求为 XAML 架构 (xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml") 添加 XAML 命名空间声明。 生成的 partial 类实现 InitializeComponent 方法,注册事件和设置在标记中实现的属性时将调用此方法。

  • 在代码隐藏中,类必须是 partial 类、名称必须是标记中 x:Class 属性指定的相同名称,并且它必须派生自 Window。 这样,代码隐藏文件就与应用程序生成时为标记文件生成的 partial 类相关联

  • 在代码隐藏中,Window 类必须实现调用 InitializeComponent 方法的构造函数。 InitializeComponent 由标记文件已生成的 partial 类实现,用以注册事件并设置标记中定义的属性。

 

2.MVVM架构原理

基于数据绑定和命令模式实现:

  • 数据绑定:视图和视图模型之间通过数据绑定来实现交互。当视图模型中的数据发生变化时,视图会自动更新相应的内容,从而实现了视图和视图模型之间的数据同步。
  • 命令模式:视图和视图模型之间通过命令模式来实现交互。视图中的用户交互事件会被转换为命令,然后传递给视图模型进行处理。

MVVM架构的核心在于将视图和模型完全解耦,视图只负责渲染用户界面,而视图模型负责处理业务逻辑和数据操作。视图和视图模型之间通过数据绑定和命令模式进行交互,从而实现了解耦和职责分离。

实例场景:两个输入值,计算他们的和,得到一个结果

ViewModel基类:

namespace WpfApp1.ViewModels
{    
    class NotificationObject : INotifyPropertyChanged
    {
        //ViewModel的某个属性借助Binding关联到View上的控件属性
        //Binding会侦听该事件的发生(属性值更改时发生),并把改变后的属性值发送到界面
        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(string propertyName)
        {
            if(this.PropertyChanged!=null)
            {
                //触发属性更改事件
                this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

ViewModel类:

namespace WpfApp1.ViewModels
{
    class MainWindowViewModel:NotificationObject
    {
        private double input1;
        public double Input1
        {
            get { return input1; }
            set{
                input1 = value;
                this.RaisePropertyChanged("Input1");
            }
        }

        private double input2;
        public double Input2
        {
            get { return input2; }
            set
            {
                input2 = value;
                this.RaisePropertyChanged("Input2");
            }
        }

        private double result;
        public double Result
        {
            get { return result; }
            set
            {
                result = value;
                this.RaisePropertyChanged("Result");
            }
        }

        public DelegateCommand AddCommand { get; set; }

        private void Add(object paramater)
        {
            //属性值改变,触发set,通知binding
            this.Result = Input1 + Input2;
        }

        public MainWindowViewModel()
        {
            //初始化命令
            this.AddCommand=new DelegateCommand ();
            this.AddCommand.ExcuteAction = new Action<object>(Add);
        }
    }
}

DelegateCommand类:

namespace WpfApp1.Command
{
    class DelegateCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            if (this.CanExcuteFunc == null)
                return true;
            return this.CanExcuteFunc(parameter);
        }
        
        //定义调用此命令时要调用的方法
        public void Execute(object parameter)
        {
            if (ExcuteAction == null)
                return;
            //执行这个委托传递的方法
            this.ExcuteAction(parameter);
        }

        public Action<object> ExcuteAction { get; set; }

        public Func<object, bool> CanExcuteFunc { get; set; }  
    }
}