WPF MVVM初體驗


首先MVVM設計模式的結構,

 

Views: 由Window/Page/UserControl等構成,通過DataBinding與ViewModels建立關聯;

ViewModels:由一組命令,可以綁定的屬性,操作邏輯構成;因為View與ViewModel進行了解耦,我們可以對ViewModel進行Unit Test;

Models:可以是實體對象或者Web服務;

下面通過一個簡單的例子,來介紹一些WPF MVVM模式。示例將展示一個圖片瀏覽器,打開圖片,放大/縮小圖片大小。首先項目結構:

UI:

    <Grid>
        <DockPanel>
            <Menu DockPanel.Dock="Top">
                <Menu>
                    <MenuItem Header="_Open" Command="{Binding OpenFileCommand}"/>
                </Menu>
                <Menu>
                    <MenuItem Header="_ZoomIn" Command="{Binding ZoomCommand}" CommandParameter="ZoomIn"/>
                </Menu>
                <Menu>
                    <MenuItem Header="_ZoomOut" Command="{Binding ZoomCommand}" CommandParameter="ZoomOut"/>
                </Menu>
                <Menu>
                    <MenuItem Header="_Normal" Command="{Binding ZoomCommand}" CommandParameter="Normal"/>
                </Menu>
            </Menu>
            <ScrollViewer>
                <Image Source="{Binding ImagePath}" Stretch="None">
                    <Image.LayoutTransform>
                        <ScaleTransform ScaleX="{Binding Zoom}" ScaleY="{Binding Zoom}"/>
                    </Image.LayoutTransform>
                </Image>
            </ScrollViewer>
        </DockPanel>
    </Grid>

ViewModelBase(用來實現修改通知):

    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propName)
        {
            if(PropertyChanged!=null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }
    }

OpenFileCommand:

public class OpenFileCommand : ICommand
    {
        private MainViewModel _data;
        public OpenFileCommand(MainViewModel data)
        {
            _data = data;
        }

        public event EventHandler CanExecuteChanged;

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

        public void Execute(object parameter)
        {
            OpenFileDialog dialog = new OpenFileDialog() { Filter = "Image Files|*.jpg;*.png;*.bmp;*.gif" };

            if(dialog.ShowDialog().GetValueOrDefault())
            {
                _data.ImagePath = dialog.FileName;
            }
        }

ZoomCommand:

    public enum ZoomType
    {
        ZoomIn = 0,
        ZoomOut = 1,
        Normal = 2
    }

    public class ZoomCommand : ICommand
    {
        private MainViewModel _data;

        public ZoomCommand(MainViewModel data)
        {
            _data = data;
        }

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

        public bool CanExecute(object parameter)
        {
            return _data.ImagePath != null;
        }

        public void Execute(object parameter)
        {
            ZoomType type = (ZoomType)Enum.Parse(typeof(ZoomType), (string)parameter, true);

            switch(type)
            {
                case ZoomType.Normal:
                    _data.Zoom = 1;
                    break;
                case ZoomType.ZoomIn:
                    _data.Zoom *= 1.2;
                    break;
                case ZoomType.ZoomOut:
                    _data.Zoom /= 1.2;
                    break;
            }
        }
    }

MainViewModel:

public class MainViewModel : ViewModelBase
    {
        private string _imagePath;

        public string ImagePath
        {
            get
            {
                return _imagePath;
            }
            set
            {
                if (_imagePath != value)
                {
                    _imagePath = value;
                    OnPropertyChanged("ImagePath");
                }
            }
        }

        private double _zoom = 1.0;

        public double Zoom
        {
            get
            {
                return _zoom;
            }
            set
            {
                if(_zoom != value)
                {
                    _zoom = value;
                    OnPropertyChanged("Zoom");
                }
            }
        }

        private ICommand _openFileCommand;

        public ICommand OpenFileCommand
        {
            get { return _openFileCommand; }
        }

        private ZoomCommand _zoomCommand;

        public ZoomCommand ZoomCommand
        {
            get { return _zoomCommand; }
        }

        public MainViewModel()
        {
            _openFileCommand = new OpenFileCommand(this);
            _zoomCommand = new ZoomCommand(this);
        }
    }


下一步我們要做的是將MainViewModel綁定到MainWindow上,我們可以通過下面兩種方式綁定:
1. 直接在MainWindow的Code Behind中進行綁定:

        public MainWindow()
        {
            InitializeComponent();

            DataContext = new MainViewModel();
        }

2. 在App.xaml后台代碼中綁定(將App.xaml中StartupUri="MainWindow.xaml"刪除掉):

        public App()
        {
            MainWindow window = new MainWindow();
            window.DataContext = new MainViewModel();
            window.Show();
        }

程序運行效果如下:

到此為止,這個簡單的示例就算完成了。點擊這里下載代碼。

感謝您的閱讀。


免責聲明!

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



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