Я новичок в C # и MVVM, поэтому я могу что-то делать не так.Я создал окно (называемое LoginMenu) и добавил userControl для чата, занимающий 1/3 окна.Затем я создал ViewModel и модель для этого чата userControl.Моя модель чата обновляется сокетом при получении любого сообщения от клиента.Похоже, что мое поле беседы обновляется в модели, но PropertyChanged в моем ChatViewModel имеет значение null.Текстовое поле моего разговора корректно обновлялось до того, как я начал использовать сокеты.Я прочитал в Интернете, что это может быть из-за того, что мой поток пользовательского интерфейса не обновлялся, поскольку он не работает в том же потоке, что и мой сокет.Это кажется маловероятным, поскольку даже мой ChatViewModel не получает правильное событие PropertyChanged.
Вот некоторые фрагменты кода: LoginMenu.xaml:
<Window.DataContext>
<viewmodels:LoginMenuVM />
</Window.DataContext>
<Window.Resources>
<DataTemplate x:Name="mainMenuOnlineTemplate" DataType="{x:Type viewmodels:MainMenuOnlineVM}">
<views:MainMenuOnline DataContext="{Binding}"/>
</DataTemplate>
<DataTemplate x:Name="chatTemplate" DataType="{x:Type viewmodels:ChatVM}">
<views:Chat DataContext="{Binding}"/>
</DataTemplate>
</Window.Resources>
...
<views:Chat Grid.Column="1"></views:Chat>
LoginMenu.xaml.cs:
public partial class LoginMenu : Window
{
public LoginMenu()
{
InitializeComponent();
this.DataContext = new LoginMenuVM();
}
}
LoginMenuViewModel:
public class LoginMenuVM : ViewModelBase
{
private SocketService socketService = new SocketService();
private User user = new User();
private ChatVM chatVM = new ChatVM();
...
public void ConnectUser(object obj)
{
if (NameIsIncorrect())
{
MessageBox.Show("Username is incorrect!");
return;
}
else
{
AssignName(potentialName);
socketService.Start(ipAdress);
try
{
string authentification_informations = user.Name;
socketService.SendDemand(authentification_informations);
{
chatVM.connectSocket(socketService, user);
} catch (Exception ex)
{
}
}
}
Chat.xaml:
<UserControl.DataContext>
<viewmodels:ChatVM />
</UserControl.DataContext>
<DockPanel Background="White">
<TextBlock DockPanel.Dock="Top" x:Name="name" Text="Name" Background="LightGray" />
<TextBox DockPanel.Dock="Bottom" Height="50" Name="messageEntry" Text="{Binding ChatBoxMessage, UpdateSourceTrigger=PropertyChanged}" >
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding SendMessageCommand}" CommandParameter="{Binding Path=Text, RelativeSource={RelativeSource AncestorType={x:Type TextBox}}}" />
</TextBox.InputBindings>
</TextBox>
<TextBlock x:Name="Conversation" Text="{Binding Path=Conversation, Mode=TwoWay}" />
</DockPanel>
ChatViewModel:
public class ChatVM : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
private static SocketService socketService;
private static User user;
private static Chat chat;
public string Conversation
{
get { return chat.Conversation; }
set { NotifyPropertyChanged(); }
}
private string _chatBoxMessage = "Enter Message";
public string ChatBoxMessage
{
get { return _chatBoxMessage; }
set
{
_chatBoxMessage = value;
NotifyPropertyChanged("ChatBoxMessage");
}
}
public RelayCommand<object> SendMessageCommand { get; set; }
public ChatVM()
{
chat = new Chat();
SendMessageCommand = new RelayCommand<object>(SendMessage);
}
public void SendMessage(object obj)
{
if (socketService != null) {
if (!string.IsNullOrWhiteSpace(ChatBoxMessage))
{
socketService.SendDemand(user.Name + ":" + ChatBoxMessage);
MessageBox.Show(Conversation);
}
else {
MessageBox.Show("You can't send empty or only white space messages.");
}
}
else {
MessageBox.Show("You can't send messages since you're not connected.");
}
}
public void connectSocket (SocketService socketServiceTemp, User userTemp)
{
user = userTemp;
socketService = socketServiceTemp;
chat = socketService.GetChat();
chat.PropertyChanged += Conversation_CollectionChanged;
}
private void Conversation_CollectionChanged(object sender, PropertyChangedEventArgs e)
{
Conversation = chat.Conversation;
}
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (PropertyChanged != null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Chat.cs:
public class Chat : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _conversation = "Test";
public string Conversation
{
get { return _conversation; }
set
{
_conversation = value;
NotifyPropertyChanged();
}
}
private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (PropertyChanged != null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
SocketService.cs:
private void TreatAnswer(IAsyncResult ar)
{
int messageReceivedInInt = socket.EndReceive(ar);
//Transform Bytes received to string
App.Current.Dispatcher.BeginInvoke((Action)delegate
{
chat.Conversation += messageReceived;
Thread.Sleep(100);
});
Thread.Sleep(100);
socket.BeginReceive(byteMessage, 0, 2048, SocketFlags.None, TreatAnswer, socket);
}
Я пытался использовать
App.Current.Dispatcher.BeginInvoke((Action)delegate
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
Thread.Sleep(100);
});
в обоих Chat.cs NotifyPropertyChanged и ChatViewModel NotifyPropertyChanged.
Как упоминалось выше, когда я добавляю точку останова к NotifyPropertyChanged ChatViewModel, PropertyChanged имеет значение null.Могу ли я заставить этот код работать?Это похоже на небольшую ошибку, но я не могу ее найти.
РЕДАКТИРОВАТЬ:
Я нашел проблему.Мне пришлось позвонить:
chat.PropertyChanged += new PropertyChangedEventHandler(Conversation_CollectionChanged);
Внутри функции SendMessage моего ChatVM, чтобы вызвать правильное событие.