Соответствующая реализация шаблона MVVM в WPF
Всем привет,
Я создал Простое Приложение Для Чата используя WPF/WCF, и у меня есть сомнения, правильно ли я реализовал в нем шаблон MVVM.
Главное окно чата имеет базовую модель представления, которая назначается свойству window DataContext (стандартное решение, я думаю):
class ChatWindowViewModel : INotifyPropertyChanged, IChatCallback { //fields and properties public ChatService.ChatClient client; InstanceContext instanceContext; public bool askToExitApp; private User chatUser; public User ChatUser { get { return chatUser; } set { chatUser = value; OnPropertyChanged("ChatUser"); } } // storage for all logged users, they will be shown in datagrid public ObservableCollection<User> AllActiveUsers { get; set; } // storage for all sent messages, they will be shown in datagrid public ObservableCollection<ChatMessage> AllMessages { get; set; } // storage for a message, being typed by user in chat public ChatMessage CurrentMessage { get; set; } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } //implementation of the IChatCallback callback interface public void UserSentMessage(ChatMessageDTO msgDTO){ ... } public void UserJoined(ChatMessageDTO msgDTO) { ... } public void UserLeft(ChatMessageDTO msgDTO) { ... } public void IsAlive() { ... } //constructor public ChatWindowViewModel() { instanceContext = new InstanceContext(this); askToExitApp = true; AllActiveUsers = new ObservableCollection<User>(); AllMessages = new ObservableCollection<ChatMessage>(); CurrentMessage = new ChatMessage(); ChatUser = new User { Nickname = string.Empty }; } //commands and everything related to them private ICommand chatWindowLoadedCommand; public ICommand ChatWindowLoadedCommand { ... } private void ChatWindowLoaded() { ... } . . }
Свойство ChatUser.Nickname из модели представления привязано к заголовку главного окна чата в соответствующем файле XAML, так что имя пользователя отображается в строке заголовка окна при входе пользователя в систему.
На стороне сервера реализован чат-сервис со следующими контрактами:
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IChatCallback))] interface IChat { [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)] void SendMessage(ChatMessageDTO msg); [OperationContract(IsOneWay = false, IsInitiating = true, IsTerminating = false)] string Join(UserDTO user, out UserDTO[] activeUsers); [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = true)] void Leave(); }
Прежде чем пользователь сможет начать общаться в чате, он должен войти в систему. В окне входа в систему можно указать псевдоним, который будет сверен с псевдонимами вошедших в систему пользователей.
Для того чтобы использовать уже определенные методы и свойства в ChatWindowViewModel, например:
- привязать текстовое поле окна входа в систему (где пользователь вводит свой ник) к свойству ChatUser.Nickname
- проверить, не выбрал ли уже какой-либо зарегистрированный пользователь указанный ник (используя сервис Join contract),
Я назначил ChatWindowViewModel свойству DataContext окна входа в систему:
private void ChatWindowLoaded() { client = new ChatService.ChatClientinstanceContext); client.Open(); bool? ret = true; using (LoginDialog loginDlg = new LoginDialog()) { loginDlg.DataContext = this; //!!!! is this ok? ret = loginDlg.ShowDialog(); } // in case user do not want to login, // close chat window client application if (ret == false) MainWindowRequestCloseCommand.Execute(null); }
Таким образом, я мог использовать функциональных возможностей, определенных в ChatWindowViewModel, в окне входа в систему, например такой:
// memeber of LoginWindow class private void DummyHandler(object sender, EventArgs e) { try { UserDTO[] activeUsers; string result = ((ChatWindowViewModel)DataContext).client.Join(((ChatWindowViewModel)DataContext).ChatUser.ToUserDTO(), out activeUsers); if (result != "OK") { MessageBox.Show(result); ((ChatWindowViewModel)DataContext).askToExitApp = false; DialogResult = false; } else { ((ChatWindowViewModel)DataContext).CurrentMessage.Sender = ((ChatWindowViewModel)DataContext).ChatUser; foreach (var user in activeUsers.OrderBy(x => x.Nickname).Select(x => x.ToUser())) ((ChatWindowViewModel)DataContext).AllActiveUsers.Add(user); DialogResult = true; Close(); } } catch (Exception ex) { MessageBox.Show("Unexpected error occured. Application will be terminated."); ((ChatWindowViewModel)DataContext).askToExitApp = false; DialogResult = false; Close(); } }
Наконец, вернемся к вопросу: правильно ли это делать что-то подобное в MVVM?
Что я уже пробовал:
Может быть, я был немного длинноват в своем описании, извиняясь за это, я просто хотел объяснить, что я пытался сделать. Спасибо за комментарии.