MVVM - implementing 'IsDirty' functionality to a ModelView in order to save data

前端 未结 7 1466
攒了一身酷
攒了一身酷 2021-02-04 07:13

Being new to WPF & MVVM I struggling with some basic functionality.

Let me first explain what I am after, and then attach some example code...

I have a scree

7条回答
  •  长情又很酷
    2021-02-04 08:06

    I have come up with a working solution. This may of course not be the best way, but I am sure I can work on it as I learn more...

    When I run the project, if I cange any item, the list box is disabled, and the save button enabled. If I undo my edits, then the list box is enabled again, and the save button disabled.

    I have changed my User Model to implement INotifyPropertyChanged, and I have also created a set of private variables to store the "original values" and some logic to check for "IsDirty"

    using System.ComponentModel;
    namespace Test.Model
    {
        public class User : INotifyPropertyChanged
        {
        //Private variables
        private string _username;
        private string _surname;
        private string _firstname;
    
        //Private - original holders
        private string _username_Orig;
        private string _surname_Orig;
        private string _firstname_Orig;
        private bool _isDirty;
    
        //Properties
        public string UserName
        {
            get
            {
                return _username;
            }
            set
            {
                if (_username_Orig == null)
                {
                    _username_Orig = value;
                }
                _username = value;
                SetDirty();
            }
        }
        public string Surname
        {
            get { return _surname; }
            set
            {
                if (_surname_Orig == null)
                {
                    _surname_Orig = value;
                }
                _surname = value;
                SetDirty();
            }
        }
        public string Firstname
        {
            get { return _firstname; }
            set
            {
                if (_firstname_Orig == null)
                {
                    _firstname_Orig = value;
                }
                _firstname = value;
                SetDirty();
            }
        }
    
        public bool IsDirty
        {
            get
            {
                return _isDirty;
            }
        }
    
        public void SetToClean()
        {
            _username_Orig = _username;
            _surname_Orig = _surname;
            _firstname_Orig = _firstname;
            _isDirty = false;
            OnPropertyChanged("IsDirty");
        }
    
        private void SetDirty()
        {
            if (_username == _username_Orig && _surname == _surname_Orig && _firstname == _firstname_Orig)
            {
                if (_isDirty)
                {
                    _isDirty = false;
                    OnPropertyChanged("IsDirty");
                }
            }
            else
            {
                if (!_isDirty)
                {
                    _isDirty = true;
                    OnPropertyChanged("IsDirty");
                }
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
    
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
    

    Then, my ViewModel has changed a bit too....

    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Windows.Input;
    using Test.Model;
    using System.ComponentModel;
    
    namespace Test.ViewModel
    {
        class UserViewModel : ViewModelBase
        {
            //Private variables
    
        private ObservableCollection _users;
        RelayCommand _userSave;
        private User _selectedUser = new User();
    
        //Properties
        public ObservableCollection User
        {
            get
            {
                if (_users == null)
                {
                    _users = new ObservableCollection();
                    _users.CollectionChanged += (s, e) =>
                    {
                        if (e.Action == NotifyCollectionChangedAction.Add)
                        {
                            // handle property changing
                            foreach (User item in e.NewItems)
                            {
                                ((INotifyPropertyChanged)item).PropertyChanged += (s1, e1) =>
                                    {
                                        OnPropertyChanged("EnableListBox");
                                    };
                            }
                        }
                    };
                    //Populate with users
                    _users.Add(new User {UserName = "Bob", Firstname="Bob", Surname="Smith"});
                    _users.Add(new User {UserName = "Smob", Firstname="John", Surname="Davy"});
                }
                return _users;
            }
        }
    
        public User SelectedUser
        {
            get { return _selectedUser; }
            set { _selectedUser = value; }
        }
    
        public bool EnableListBox
        {
            get { return !_selectedUser.IsDirty; }
        }
    
        //Commands
        public ICommand UserSave
        {
            get
            {
                if (_userSave == null)
                {
                    _userSave = new RelayCommand(param => this.UserSaveExecute(), param => this.UserSaveCanExecute);
                }
                return _userSave;
            }
        }
    
        void UserSaveExecute()
        {
            //Here I will call my DataAccess to actually save the data
            //Save code...
            _selectedUser.SetToClean();
            OnPropertyChanged("EnableListBox");
        }
    
        bool UserSaveCanExecute
        {
            get
            {
                return _selectedUser.IsDirty;
            }
        }
    
        //constructor
        public UserViewModel()
        {
    
        }
    
    }
    

    Finally, the XAML I changed the bindings on the Username, Surname & Firstname to include UpdateSourceTrigger=PropertyChanged And then I bound the listbox's SelectedItem and IsEnabled

    As I said in the beginning - it may not be the best solution, but it seems to work...

提交回复
热议问题