欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

WPF随笔(十二)--使用MVVM模式

程序员文章站 2022-07-13 22:30:17
...

规模稍大的WPF项目一般会采用MVVM模式,常见的框架有Prism、MvvmLight、Caliburn等。今天就从头开始创建一个使用MVVM模式的WPF项目,对MVVM也能有一个更好的了解。


1.实现INotifyPropertyChanged接口

实现INotifyPropertyChanged接口是为了利用WPF的数据绑定特性,当数据源发生变化时,能及时通知UI层进行刷新,避免手动刷新UI的问题。

    public class ViewModelBase : INotifyPropertyChanged
    {

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        protected internal virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion

    }

2.实现ICommand接口

WPF默认的交互方式是事件驱动的,即UI层的动作触发路由事件,数据层在路由事件的函数中进行相应处理。实现ICommand接口是为了将UI层和数据层解耦,避免绑定路由事件时的强关联。

public class DelegateCommands<T> : ICommand
    {
        private readonly Action<T> _executeMethod = null;
        private readonly Func<T, bool> _canExecuteMethod = null;

        public DelegateCommands(Action<T> executeMethod)
            : this(executeMethod, null)
        { }

        public DelegateCommands(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
        {
            if (executeMethod == null)
                throw new ArgumentNullException("executeMetnod");
            _executeMethod = executeMethod;
            _canExecuteMethod = canExecuteMethod;
        }

        #region ICommand 成员
        /// <summary>
        ///  Method to determine if the command can be executed
        /// </summary>
        public bool CanExecute(T parameter)
        {
            if (_canExecuteMethod != null)
            {
                return _canExecuteMethod(parameter);
            }
            return true;

        }

        /// <summary>
        ///  Execution of the command
        /// </summary>
        public void Execute(T parameter)
        {
            if (_executeMethod != null)
            {
                _executeMethod(parameter);
            }
        }

        #endregion


        event EventHandler ICommand.CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        #region ICommand 成员

        public bool CanExecute(object parameter)
        {
            if (parameter == null && typeof(T).IsValueType)
            {
                return (_canExecuteMethod == null);

            }

            return CanExecute((T)parameter);
        }

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

        #endregion
    }

3.创建ViewModel

新建MainWindowViewModel类,继承自上面的ViewModelBase类,用于命令的绑定触发和数据的处理通知。

    public class MainWindowViewModel:ViewModelBase
    {
        public MainWindowViewModel()
        {
        	//命令绑定
            AddCommand = new DelegateCommands<string>(Add);
            EditCommand = new DelegateCommands<DetailGoodsDto>(Edit);
            DeleteCommand = new DelegateCommands<DetailGoodsDto>(Delete);
			//数据初始化
            InitData();
        }

        #region Properties-属性
        private List<DetailGoodsDto> _goodsList;

        public List<DetailGoodsDto> GoodsList
        {
            get { return _goodsList; }
            set
            {
                if (_goodsList != value)
                {
                    _goodsList = value;
                    OnPropertyChanged("GoodsList");
                }
            }
        }
        #endregion

        #region Commands-命令
        public DelegateCommands<string> AddCommand { get; set; }
        public DelegateCommands<DetailGoodsDto> EditCommand { get; set; }
        public DelegateCommands<DetailGoodsDto> DeleteCommand { get; set; }
        #endregion

        #region Methods-方法
        private void InitData()
        {
            GoodsList = new List<DetailGoodsDto>()
            {
            	new DetailGoodsDto
            	{
            		GoodsName="矿泉水",
            		GoodsType="酒水饮料",
            		Location="1号库",
            		GoodsNum=100
				}
			};
            
        }

        private void Add(string obj)
        {
        	//to do
        }

        private void Edit(DetailGoodsDto obj)
        {
            //to do
        }

        private void Delete(DetailGoodsDto obj)
        {
            //to do
        }
        #endregion

    }

4.修改View并绑定数据上下文

修改MainWindow.xaml,与MainWindowViewModel中的属性和命令一一对应。

<Window x:Class="AbpDemo.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:AbpDemo.Client"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition Height="80"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <WrapPanel Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Right">
            <Button Command="{Binding AddCommand}" CommandParameter="Add">添加</Button>
            <Button Command="{Binding EditCommand}" CommandParameter="{Binding ElementName=GoodsData,Path=SelectedItem}">编辑</Button>
            <Button Command="{Binding DeleteCommand}" CommandParameter="{Binding ElementName=GoodsData,Path=SelectedItem}">删除</Button>
        </WrapPanel>
        <DataGrid x:Name="GoodsData" Grid.Row="1" AutoGenerateColumns="False" SelectionUnit="FullRow" ItemsSource="{Binding GoodsList}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="货品名称" Width="*" Binding="{Binding GoodsName}"></DataGridTextColumn>
                <DataGridTextColumn Header="货品类型" Width="*" Binding="{Binding GoodsType}"></DataGridTextColumn>
                <DataGridTextColumn Header="存放位置" Width="*" Binding="{Binding Location}"></DataGridTextColumn>
                <DataGridTextColumn Header="货品数量" Width="*" Binding="{Binding GoodsNum}"></DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

同时修改MainWindow.xaml.cs以建立View视图层与ViewModel视图模型层的关联关系。

    public partial class MainWindow : Window
    {
        private MainWindowViewModel _viewModel;

        public MainWindow()
        {
            _viewModel = new MainWindowViewModel();
            this.DataContext = _viewModel;//设置数据上下文
            InitializeComponent();
        }
    }

以上步骤就完成了最简单的MVVM模式。


相关标签: WPF WPF MVVM