Search code examples
c#wpfdata-bindingbinding-expressions

C# WPF BindingExpression path error in ListView


I am writing a chatprogram, and I have a page where the user can select saved chathistories. They are all in a ListView with 2 columns: Date and Partner. To have 2 columns, I found a solution by writing my own entry class (Add Items to Columns in a WPF ListView). This is my MessageHistoryEntry:

public class MessageHistoryEntry : ListViewItem
{
    public int EpochTime { get { return int.Parse(this.Content.ToString().Split("|")[0]); } }
    public string[] Usernames { get { return this.Content.ToString().Split("|").Skip(1).ToArray(); } }
    public string Partner { get { return this.Content.ToString().Split("|").Skip(1).ToArray()[0]; } }

    public string Entrystring { get { return this.Content.ToString(); } set { this.Content = value; } }
    public string TimeString { get {                    
    DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(int.Parse(this.Content.ToString().Split("|")[0]));
    return dateTimeOffset.ToString(); } }
}

The entrystring is a specially formatted string: <timeinepoch>"|"<partner>("|"<othermembers>)+, for e.g. 1619819688|ExampleUser1|ExampleUser2

So I have a ListView with 2 columns, and if the user clicks on an item (I found how to add clickevent here: WPF ListView - detect when selected item is clicked), it loads the corresponding chat conversation.

The ListView:

<ListView Margin="0,0,1027,112" x:Name="ChatHistoryListView" >
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Date" DisplayMemberBinding="{Binding TimeString}"/>
            <GridViewColumn Header="Partner" DisplayMemberBinding="{Binding Partner}"/>
        </GridView>
    </ListView.View>


    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <EventSetter Event="PreviewMouseLeftButtonDown" Handler="SelectSaveHistory" />
        </Style>
    </ListView.ItemContainerStyle>


</ListView>

My problem is, whenever I try to fill the list, I get the following errors:

System.Windows.Data Error: 40 : BindingExpression path error: 'TimeString' property not found on 'object' ''String' (HashCode=808077091)'. BindingExpression:Path=TimeString; DataItem='String' (HashCode=808077091); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Error: 40 : BindingExpression path error: 'Partner' property not found on 'object' ''String' (HashCode=808077091)'. BindingExpression:Path=Partner; DataItem='String' (HashCode=808077091); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

But when I click on it, it gives me the correct information, and loads the chathistory correctly, so the content is right, only the display is faulty.

So my question is, how could I display those data members in my ListView columns?


The way I fill the ListView:

private void BeginHistory(object sender, RoutedEventArgs e)
{           
    string[] histories = misc.GetUserHistoryIDs(curUser.Username); ///getting the chathistory id elements from a controller

    foreach(string history in histories)
    {
        MessageHistoryEntry entry = new MessageHistoryEntry();

        entry.Entrystring = history; ///setting the entrystring, which is equivalent to the content now

        ChatHistoryListView.Items.Add(entry); ///adding the entry to the list
    }

}

Solution

  • don't inherit MessageHistoryEntry from ListViewItem. ListView will creates ListViewItems for your data items. Items collection can contains objects of any type, even different types at the same time

    also don't do multiple splits:

    public class MessageHistoryEntry
    {
        public int EpochTime { get; private set; }
        public string TimeString { get; private set; }
        public string[] Usernames { get; private set; }
        public string Partner { get; private set; }
    
        string  entrystring;
        public string Entrystring 
        { 
             get { return entrystring; } 
             set 
             { 
                 entrystring = value; 
    
                 var parts = entrystring.Split("|"); 
                 EpochTime = int.Parse(parts[0]); 
                 TimeString = DateTimeOffset.FromUnixTimeSeconds(EpochTime).ToString();
                 Usernames = parts.Skip(1).ToArray();
                 Partner = Usernames[0];             
             } 
         }
    }