One ViewModel for UserControl and Window or separate ViewModels

前端 未结 2 1246
我在风中等你
我在风中等你 2020-12-01 17:36

I have MainWindow and AddEdit UserControl. Inside MainWindow I render this AddEdit like

2条回答
  •  离开以前
    2020-12-01 18:01

    Part 1. Display the properties of the control in MVVM

    As I said in comments:

    In MVVM ViewModel should not know about the controls, which are located. In such cases, use the attached behavior or leave the same side logic in View

    ViewModel is not directly associated with a View, so just refer to the name of the control would not be right. It would be better to set a property in the Model, and bind it into View via ViewModel, but the property Name does not support Binding (quote from the MSDN):

    Data binding a Name is technically possible, but is an extremely uncommon scenario because a data-bound Name cannot serve the main intended purpose of the property: to provide an identifier connection point for code-behind.

    so I suggest to use the Tag property or Uid. In my example (give an below), I use Uid property for these purposes.

    Part 2. Communication via ViewModels (pattern Mediator)

    There are several embodiments of the Mediator pattern, but I like the most the implementation by XAML Guy, it is simple and clear - The Mediator Pattern.

    Implementation code

    public static class Mediator
    {
        static IDictionary>> pl_dict = new Dictionary>>();
    
        static public void Register(string token, Action callback)
        {
            if (!pl_dict.ContainsKey(token))
            {
                var list = new List>();
                list.Add(callback);
                pl_dict.Add(token, list);
            }
            else
            {
                bool found = false;
                foreach (var item in pl_dict[token])
                    if (item.Method.ToString() == callback.Method.ToString())
                        found = true;
                if (!found)
                    pl_dict[token].Add(callback);
            }
        }
    
        static public void Unregister(string token, Action callback)
        {
            if (pl_dict.ContainsKey(token))
            {
                pl_dict[token].Remove(callback);
            }
        }
    
        static public void NotifyColleagues(string token, object args)
        {
            if (pl_dict.ContainsKey(token))
            {
                foreach (var callback in pl_dict[token])
                    callback(args);
            }
        }
    }
    
    
    

    To demonstrate his work, I created a small example, which consists of two Views, each has its own ViewModel and Model.

    The project structure is shown below:

    Project structure

    Output

    Using example

    When you click on Button, ListOfData ViewModel communicates via mediator with DataDetails ViewModel, thus:

    Mediator.NotifyColleagues("ShowDetails", true);
    Mediator.NotifyColleagues("SetSelectedFruit", ListOfDataModel.FruitGreen);
    

    All procedures that interact with the properties must register their ViewModel like this:

    private void ShowDetails_Mediator(object args)
    {
        bool showDetails = (bool)args;
    
        if (showDetails == true)
        {
            DataDetailsModel.IsVisible = true;
        }
        else
        {
            DataDetailsModel.IsVisible = false;
        }
    }
    
    private void SetSelectedFruit_Mediator(object args)
    {
        string selectedFruit = (string)args;
    
        DataDetailsModel.SelectedFruit = selectedFruit;
    }
    
    public DataDetailsViewModel() 
    {
        DataDetailsModel = new DataDetailsModel();
    
        Mediator.Register("ShowDetails", ShowDetails_Mediator);
        Mediator.Register("SetSelectedFruit", SetSelectedFruit_Mediator);
    }
    

    In the example I used a DataTemplate instead UserControl. Below are the main part of the project:

    MainWindow.xaml

    
    
        
            
    
                            
            
    
            
    
                
            
        
     
    

    Models

    DataDetailsModel

    public class DataDetailsModel : NotificationObject
    {
        #region SelectedFruit
    
        private string _selectedFruit = "";
    
        public string SelectedFruit
        {
            get
            {
                return _selectedFruit;
            }
    
            set
            {
                _selectedFruit = value;
                NotifyPropertyChanged("SelectedFruit");
            }
        }
    
        #endregion
    
        #region IsVisible
    
        private bool _isVisible = false;
    
        public bool IsVisible
        {
            get
            {
                return _isVisible;
            }
    
            set
            {
                _isVisible = value;
                NotifyPropertyChanged("IsVisible");
            }
        }
    
        #endregion
    }
    

    ListOfDataModel

    public class ListOfDataModel : NotificationObject
    {
        #region FruitGreen
    
        private string _fruitGreen = "Apple";
    
        public string FruitGreen
        {
            get
            {
                return _fruitGreen;
            }
    
            set
            {
                _fruitGreen = value;
                NotifyPropertyChanged("FruitGreen");
            }
        }
    
        #endregion
    
        #region FruitYellow
    
        private string _fruitYellow = "Limon";
    
        public string FruitYellow
        {
            get
            {
                return _fruitYellow;
            }
    
            set
            {
                _fruitYellow = value;
                NotifyPropertyChanged("FruitYellow");
            }
        }
    
        #endregion
    }
    

    ViewModels

    DataDetailsViewModel

    public class DataDetailsViewModel
    {
        #region DataDetailsModel
    
        private DataDetailsModel _dataDetailsModel = null;
    
        public DataDetailsModel DataDetailsModel
        {
            get
            {
                return _dataDetailsModel;
            }
    
            set
            {
                _dataDetailsModel = value;
            }
        }
    
        #endregion
    
        #region ShowDetails_Mediator
    
        private void ShowDetails_Mediator(object args)
        {
            bool showDetails = (bool)args;
    
            if (showDetails == true)
            {
                DataDetailsModel.IsVisible = true;
            }
            else
            {
                DataDetailsModel.IsVisible = false;
            }
        }
    
        #endregion
    
        #region SetSelectedFruit_Mediator
    
        private void SetSelectedFruit_Mediator(object args)
        {
            string selectedFruit = (string)args;
    
            DataDetailsModel.SelectedFruit = selectedFruit;
        }
    
        #endregion
    
        #region DataDetailsViewModel Constructor
    
        public DataDetailsViewModel() 
        {
            DataDetailsModel = new DataDetailsModel();
    
            Mediator.Register("ShowDetails", ShowDetails_Mediator);
            Mediator.Register("SetSelectedFruit", SetSelectedFruit_Mediator);
        }
    
        #endregion
    }
    

    ListOfDataViewModel

    public class ListOfDataViewModel
    {
        #region ListOfDataModel
    
        private ListOfDataModel _listOfDataModel = null;
    
        public ListOfDataModel ListOfDataModel
        {
            get
            {
                return _listOfDataModel;
            }
    
            set
            {
                _listOfDataModel = value;
            }
        }
    
        #endregion
    
        #region GreenButtonCommand
    
        private ICommand _greenButtonCommand = null;
    
        public ICommand GreenButtonCommand
        {
            get
            {
                if (_greenButtonCommand == null)
                {
                    _greenButtonCommand = new RelayCommand(param => this.GreenButton(), null);
                }
    
                return _greenButtonCommand;
            }
        }
    
        private void GreenButton()
        {
            Mediator.NotifyColleagues("ShowDetails", true);
            Mediator.NotifyColleagues("SetSelectedFruit", ListOfDataModel.FruitGreen);
        }
    
        #endregion
    
        #region YellowButtonCommand
    
        private ICommand _yellowButtonCommand = null;
    
        public ICommand YellowButtonCommand
        {
            get
            {
                if (_yellowButtonCommand == null)
                {
                    _yellowButtonCommand = new RelayCommand(param => this.YellowButton(), null);
                }
    
                return _yellowButtonCommand;
            }
        }
    
        private void YellowButton()
        {
            Mediator.NotifyColleagues("ShowDetails", true);
            Mediator.NotifyColleagues("SetSelectedFruit", ListOfDataModel.FruitYellow);
        }
    
        #endregion
    
        #region ListOfDataViewModel Constructor
    
        public ListOfDataViewModel() 
        {
            ListOfDataModel = new ListOfDataModel();
        }
    
        #endregion
    }
    

    Views

    DataDetailsView

    
    
        
    
        
            
    
                
                
            
            
    
    

    ListOfDataView

    
    
        
            
    
                

    This project is available at this link.

    提交回复
    热议问题