wpf之MVVM

MVVM模式早就久仰大名,wpf采用MVVM模式后,我们只需要给属性赋值即可,不再需要去手动操作界面元素,大大减少了界面的开发工作量。

本章,通过解读一个MVVM的实例,来对MVVM模式有个大概的了解。

首先大概看下结构:

 分为Models  Views    ViewModels 。取每个前面第一个字母 就是MVVM

那么这3个模块都是干嘛的呢?

Models定义了一个类

    public class TextConverter
    {
        private readonly Func<string, string> _convertion;

        public TextConverter(Func<string, string> convertion)
        {
            _convertion = convertion;
        }

        public string ConvertText(string inputText)
        {
            return _convertion(inputText);
        }
    }

大概感觉就是执行了一个外部传递进来的函数,然后进行了一些字符串转换。

再看views类

 看到了熟悉的界面配置,点开看了下,果然是界面的设计

 下面的重点看下ViewModels

定义了3个类

我们一个一个研读

DelegateCommand类 继承ICommand ,

    public class DelegateCommand : ICommand
    {
        private readonly Action _action;

        public DelegateCommand(Action action)
        {
            _action = action;
        }

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

        public bool CanExecute(object parameter)
        {
            return true;
        }

#pragma warning disable 67
        public event EventHandler CanExecuteChanged { add { } remove { } }
#pragma warning restore 67
    }

 重点就两个函数 第一个CanExecute 是否可以执行第二个Execute 执行了构造函数传递进来的函数。

ObservableObject 类

    public abstract class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChangedEvent(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

其实就是执行了PropertyChangedEventHandler事件,那么到底这个事件是干嘛的呢?其实我们不需要关心,我们等下只要关心哪里增加了这个事件即可。

Presenter类,继承上面定义的ObservableObject类

public class Presenter : ObservableObject
    {
        private readonly TextConverter _textConverter = new TextConverter(s => s.ToUpper());
        private string _someText;
        private readonly ObservableCollection<string> _history = new ObservableCollection<string>();

        public string SomeText
        {
            get { return _someText; }
            set
            {
                _someText = value;
                RaisePropertyChangedEvent("SomeText");
            }
        }

        public IEnumerable<string> History
        {
            get { return _history; }
        }

        public ICommand ConvertTextCommand
        {
            get { return new DelegateCommand(ConvertText); }
        }

        private void ConvertText()
        {
            if (string.IsNullOrWhiteSpace(SomeText)) return;
            AddToHistory(_textConverter.ConvertText(SomeText));
            SomeText = string.Empty;
        }

        private void AddToHistory(string item)
        {
            if (!_history.Contains(item))
                _history.Add(item);
        }
    }

下面看界面

    <Window.DataContext>
        <ViewModels:Presenter/>
    </Window.DataContext>

这个DataContext熟悉,其实就是wpf为MVVM准备的,Presenter是我们的一个类,在上面的VM里面,他把这个类绑定到了界面,就是干这个活。

看下面一个界面,真正的材料都在这里

<UserControl x:Class="MinimalMVVM.Views.ConverterControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:ViewModels="clr-namespace:MinimalMVVM.ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="336"
             d:DesignWidth="300"
             d:DataContext="{d:DesignInstance ViewModels:Presenter}">

    <UserControl.InputBindings>
        <KeyBinding Key="Enter" Command="{Binding ConvertTextCommand}"/>
    </UserControl.InputBindings>
    
    <StackPanel Height="336">
        <Label Foreground="Blue" Margin="5,5,5,0">Text To Convert</Label>
        <TextBox Text="{Binding SomeText, UpdateSourceTrigger=PropertyChanged}" Margin="5"/>
        <Label Foreground="Blue" Margin="5,5,5,0">History</Label>
        <ListBox ItemsSource="{Binding History}" Height="200" Margin="5"/>
        <Button Command="{Binding ConvertTextCommand}" Margin="5">Convert</Button>
    </StackPanel>
    
</UserControl>

首先:mc:Ignorable=“d"的意思就是告诉编辑器(vs2017)在项目运行时忽略命名空间d设置的大小。
d:DesignHeight=”" d:DesignWidth="" 只说明了控件设计宽度,实际运行时,会根据窗体而变化
与Width、Height不同

参考这里

https://docs.microsoft.com/zh-cn/previous-versions/visualstudio/visual-studio-2010/ee839627(v=vs.100)?redirectedfrom=MSDN

明白了

就是设计的时候,先以这个类作为数据绑定的依据,在运行的时候,再根据具体的实例来进行赋值。

<TextBox Text="{Binding SomeText, UpdateSourceTrigger=PropertyChanged}" Margin="5"/>

这里有两个地方需要注意:

第一个是Binding 后面的值,第二个是UpdateSourceTrigger

Binding对应的是这个属性,不难理解。

 UpdateSourceTrigger设置的是更新的方式,UpdateSourceTrigger一共包含有四种方式:Default,PropertyChanged,LostFocus,Explicit。

    Default: 由不同控件控制. 例如 TextBox, 当 LostFocus 事件触发时,目标绑定发生变化.
    PropertyChanged: 意味着当目标控件值发生变化时,源数据立马更新.例如, TextBox是目标绑定,当输入字符时, 源数据也发生变化. 着就意味着当你输入字符创的时候,TextBox的数据Text也在改变.
    Explicit: 当UpdateSourceTrigger 设置为 Explicit, 数据源不会自动更新,只有在后代码里面显示的触发。

这里设置的是有值变化,立刻更新。

<ListBox ItemsSource="{Binding History}" Height="200" Margin="5"/>


这里是把ListBox绑定到一个list队列,也好理解。

<Button Command="{Binding ConvertTextCommand}" Margin="5">Convert</Button>

这里的话,是把点击按钮的事件,绑定到了下面这个属性上面

 public ICommand ConvertTextCommand
        {
            get { return new DelegateCommand(ConvertText); }
        }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值