Search code examples
c#wpfxamlchat

First time developing in XAML, cannot make my chat work


First time I program an app in XAML, I learned from different sources and I am trying to make an app. Right now I am working on making a good looking chat but ran into an error that I cannot solve at all.

The part that bugs start in the MainWindow:

<chat:ChatViewModel/>

This calls the user control CharViewModel that creates the chat. Here is the XAML part of this user control:

<UserControl.Resources>
    <DataTemplate DataType="{x:Type local:IncomingMessage}">
        <Grid >
            <Border Background="Orange" CornerRadius="15 15 0 15" Margin="10 12">
                <TextBlock Margin="15" TextWrapping="Wrap" Foreground="CadetBlue" Text="{Binding MessageContent}"/>
            </Border>
            <TextBlock Text="Thu 5:45PM" HorizontalAlignment="Left" VerticalAlignment="Bottom" FontSize="10" Margin="10 0"/>
        </Grid>
    </DataTemplate>

    <DataTemplate DataType="{x:Type local:OutgoingMessage}">
        <Grid >
            <Border Background="Gray" CornerRadius="15 15 0 15" Margin="10 12">
                <TextBlock Margin="15" TextWrapping="Wrap" Foreground="CadetBlue" Text="{Binding MessageContent}"/>
            </Border>
            <TextBlock Text="Thu 5:45PM" HorizontalAlignment="Right" VerticalAlignment="Bottom" FontSize="10" Margin="10 0"/>
        </Grid>
    </DataTemplate>
</UserControl.Resources>

<UserControl.DataContext>
    <local:MessageList/>
</UserControl.DataContext>

<Grid>
    <ItemsControl ItemsSource="{Binding Messages}"/>
</Grid>

Here is the C# code:

public partial class ChatViewModel : UserControl
{
    public ChatViewModel()
    {
        InitializeComponent();
    }
}

This is how my MessageList looks like :

class MessageList : ViewModelBase
{
    public MessageList()
    {
        Messages = new ObservableCollection<Message>();
    }
    public ObservableCollection<Message> Messages { get; set; }
}

To finish, this is the code in the MainWindow.cs that creates the list of message from a text file. Each message is of the form "David/Hi how are u?" in the text file:

var ListMessage = new MessageList();
using (StreamReader file = new StreamReader("../Utilisateur/Chat.txt"))
{
    string text;
    while ((text = file.ReadLine()) != null)
    {
        string[] list = text.Split('/');
        if (list[0] == "David")
        {
            ListMessage.Messages.Add(new OutgoingMessage { MessageContent = list[1] });
        }
        else
        {
            ListMessage.Messages.Add(new IncomingMessage { MessageContent = list[1] });
        }
                    
    }
}

With the message class looking like this:

public class Message : ViewModelBase
{
    ///Sender Name
    public string SenderName { get; set; }

    ///Text of the message
    private string _messageContent;
    public string MessageContent
    {
        get
        {
            return _messageContent;
        }
        set
        {
            _messageContent = value;
            OnPropertyChanged("MessageContent");
        }
    }

    ///True if message has been read
    public bool MessageRead;
    
    ///Time the message was sent
    public DateTimeOffset MessageSentTime { get; set; }
}

And the ViewModelBase that I copied from the internet because I don't fully understand how it works

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propName = null)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propName));
        }
    }
}

Here I have a text file with each line representing a message of the form "NameOfTheTender/Message".

Then I want to display the messages as small bubble, orange and on the left side of the window if I received the message, gray and on the right side if I sent it. For the moment nothing shows on the window. How the window looks like right now


Solution

  • <local:MessageList/> in the UserControl's DataContext and new MessageList() in the Window's code behind create two different MessageList instances. Adding items to one of them has no effect on the other.

    Your UserControl should not set its own DataContext. Remove this DataContent assignment from the UserControl's XAML:

    <UserControl.DataContext>
        <local:MessageList/>
    </UserControl.DataContext>
    

    In order to make the UserControl bind to the MessageList instance created in the MainWindow, just assign that to the Window's DataContext:

    var ListMessage = new MessageList();
    DataContext = ListMessages;
    

    The value of the DataContext property will now be inherited by the UserControl.