14

I am using a BackgroundWorker in a new WPF app and I need to report progress/update the UI as it is working in the background.

I have been doing this for a long time in WIndows Forms apps. I've just rewritten it all for WPF and it's giving me a bit of a headache.

It keeps throwing the following error at runtime:

System.Windows.Data Error: 40 : BindingExpression path error: 'Sender' property not found on 'object' ''Char' (HashCode=5046349)'. BindingExpression:Path=Sender; DataItem='Char' (HashCode=5046349); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') System.Windows.Data Error: 40 : BindingExpression path error: 'Subject' property not found on 'object' ''Char' (HashCode=5046349)'. BindingExpression:Path=Subject; DataItem='Char' (HashCode=5046349); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') System.Windows.Data Error: 40 : BindingExpression path error: 'Sender' property not found on 'object' ''Char' (HashCode=6619237)'. BindingExpression:Path=Sender; DataItem='Char' (HashCode=6619237); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') System.Windows.Data Error: 40 : BindingExpression path error: 'Subject' property not found on 'object' ''Char' (HashCode=6619237)'. BindingExpression:Path=Subject; DataItem='Char' (HashCode=6619237); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') System.Windows.Data Error: 40 : BindingExpression path error: 'Sender' property not found on 'object' ''Char' (HashCode=7536755)'. BindingExpression:Path=Sender; DataItem='Char' (HashCode=7536755); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') System.Windows.Data Error: 40 : BindingExpression path error: 'Subject' property not found on 'object' ''Char' (HashCode=7536755)'. BindingExpression:Path=Subject; DataItem='Char' (HashCode=7536755); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') System.Windows.Data Error: 40 : BindingExpression path error: 'Sender' property not found on 'object' ''Char' (HashCode=7536755)'. BindingExpression:Path=Sender; DataItem='Char' (HashCode=7536755); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') System.Windows.Data Error: 40 : BindingExpression path error: 'Subject' property not found on 'object' ''Char' (HashCode=7536755)'. BindingExpression:Path=Subject; DataItem='Char' (HashCode=7536755); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') System.Windows.Data Error: 40 : BindingExpression path error: 'Sender' property not found on 'object' ''Char' (HashCode=6357089)'. BindingExpression:Path=Sender; DataItem='Char' (HashCode=6357089); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') System.Windows.Data Error: 40 : BindingExpression path error: 'Subject' property not found on 'object' ''Char' (HashCode=6357089)'. BindingExpression:Path=Subject; DataItem='Char' (HashCode=6357089); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') System.Windows.Data Error: 40 : BindingExpression path error: 'Sender' property not found on 'object' ''Char' (HashCode=6750311)'. BindingExpression:Path=Sender; DataItem='Char' (HashCode=6750311); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') System.Windows.Data Error: 40 : BindingExpression path error: 'Subject' property not found on 'object' ''Char' (HashCode=6750311)'. BindingExpression:Path=Subject; DataItem='Char' (HashCode=6750311); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') System.Windows.Data Error: 40 : BindingExpression path error: 'Sender' property not found on 'object' ''Char' (HashCode=6619237)'. BindingExpression:Path=Sender; DataItem='Char' (HashCode=6619237); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') System.Windows.Data Error: 40 : BindingExpression path error: 'Subject' property not found on 'object' ''Char' (HashCode=6619237)'. BindingExpression:Path=Subject; DataItem='Char' (HashCode=6619237); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

I have no idea what that actually means. A few Google searches didn't reveal anything that has helped.

I'll also point out that the code does actually retrieve all mails just fine if I don't use the BGWorker in WPF. But it only stops working and stops binding when I use the background worker. I have no idea why. The exact same code works in WinForms for BGWorker.

What does this error really mean and what can I do to get rid of it?

Code-behind:

public partial class MainWindow : Window
    {
        public BackgroundWorker worker = new BackgroundWorker();
        public ObservableCollection<Message> messages = new ObservableCollection<Message>();
        public MailMessage msg;
        int count = 0;

        public class Message
        {
            public string Sender { get; set; }
            public string Subject { get; set; }
            public string Content { get; set; }
            public DateTime DateReceived { get; set; }
            public DateTime DateRead { get; set; }
            public MailMessage Mail { get; set; }
        }

        public MainWindow()
        {
            InitializeComponent();

            worker.WorkerSupportsCancellation = true;
            worker.WorkerReportsProgress = true;

            worker.ProgressChanged += Worker_ProgressChanged;
            worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
            worker.DoWork += Worker_DoWork;
        }

        private void RetrieveMessages()
        {
            // Working code.
            using (var imap = new AE.Net.Mail.ImapClient())
            {
                for(int i = 0; i < count; i++)
                {
                    MailMessage msg = imap.GetMessage(i, true, false);
                    worker.ReportProgress(i);
                }
            }
        }

        private void Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            if(count != 0)
                RetrieveMessages();
            else
            {
                using(var imap = new AE.Net.Mail.ImapClient())
                {
                    count = imap.GetMessageCount("Inbox");
                }
            }
        }

        private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            status.Text = "Status: Idle.";

                list.ItemsSource = messages;
        }

        private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            Console.WriteLine(msg.Sender.Address + " " + msg.Subject);
            MessageBox.Show(msg.Subject);
            if(msg != null)
            {
                messages.Add(new Message()
                {
                    Sender = "hi",
                    Subject = msg.Subject,
                    Content = msg.Body,
                    Mail = msg
                });

                msg = null;
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // DEBUG ONLY
            worker.RunWorkerAsync();
            status.Text = "Status: Synchronizing.";
        }
    }

XAML:

    <ScrollViewer ScrollViewer.CanContentScroll="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
        <ListView x:Name="list" ItemsSource="{Binding Source=Message}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderBrush="{x:Null}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">
                        <TextBlock x:Name="senderLabel" Text="{Binding Sender}" HorizontalAlignment="Stretch" TextTrimming="WordEllipsis" TextWrapping="Wrap" FontWeight="SemiBold" />
                        <TextBlock x:Name="subjectLabel" Text="{Binding Subject}" HorizontalAlignment="Stretch" TextTrimming="WordEllipsis" TextWrapping="Wrap" />
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ScrollViewer>
jay_t55
  • 11,362
  • 28
  • 103
  • 174
  • 1
    change your ListView Binding to the Collection: ItemsSource="{Binding messages}" – Mark Jul 03 '14 at 16:02
  • @Mark, I have changed it from Message to messages in XAML but I am still having the same error show up. – jay_t55 Jul 03 '14 at 16:17
  • 1
    checked it now your not setting anything in your datacontext so a binding doesn't work in the listview remove ItemsSource="{Binding Source=Message}" than it should work because you are setting it at code behind. And you should read some articles about binding and mvvm ;) – Mark Jul 03 '14 at 16:17

3 Answers3

44

That is a DataBinding Error

Easiest way to read those is break it up by the colons/semi-colons, and read it backwards

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

  1. target property is 'Text' (type 'String')
  2. target element is 'TextBlock' (Name='');
  3. BindingExpression:Path=Sender;
  4. DataItem='Char' (HashCode=6619237);
  5. 'Sender' property not found on 'object' ''Char' (HashCode=6619237)'.
  6. BindingExpression path error:
  7. System.Windows.Data Error: 40 :

1 tells you that there is a Text property causing the error

2 tells you that the Text property is on a <TextBlock> element

3 tells you the binding express causing the problem is {Binding Path=Sender}

4 tells you the DataItem/DataContext behind the <TextBlock> element is an item of data type Char

5 tells you the actual problem with this: there is no property named Sender on the object of type Char

6 just tells you it's a binding error

7 I have no idea what it means

Since I see you have a public property named Sender on your Message class, and its clear that Message is not Char, its obvious that your DataContext for each item is wrong.

Since it is set to a Char the most likely cause is you are binding to a string, and the DataContext for each element is a character in that string.

And sure enough, ItemsSource="{Binding Source=Messages} means you are changing the binding's Source property from the current DataContext to a string. And strings are just character arrays, so it means you are binding to the character array { M, e, s, s, a, g, e, s }

If you change the Source property to the Path property, then it will correctly read DataContext.Messages instead, and should work.

<ListView ItemsSource="{Binding Path=Messages}" ... />

(The word Path here is optional, since if you don't specify a property name then the binding assumes it is the value for the Path property)


As a side note, I don't see you setting your DataContext anywhere on the form, and I don't see a public Messages property either.

The MainWindow constructor should probably have a line of code that looks like this to set the DataContext to itself :

this.DataContext = this;

And you probably need a public property for your ObservableCollection<Message> messages so the ListView binding can find it :

public ObservableCollection<Message> Messages
{
    get { return messages; }
    set { messages = value; }
}

I'm not sure if these were merely overlooked, or if you didn't know you needed them.

Oh, and if you plan on changing any of these bound properties and having the UI automatically update, you'll want to implement INotifyPropertyChanged too :)

And since I'm in tutorial-mode here, I figured I should also link to this answer :

Transitioning from Windows Forms to WPF

I would highly recommend reading through it (and the linked articles) if you're new to how WPF works, and are switching from Winforms to WPF. Which it sounds like you are :)

Community
  • 1
  • 1
Rachel
  • 130,264
  • 66
  • 304
  • 490
  • So really, I still have no idea why it's complaining to me about this. The type that I am "passing" to it is `string`, so I don't know why it's telling me it's `char`. I think it has something to do with the BackgroundWorker. Only reason I think this is because the same code works fine without the BGWorker. Were you using a BackgroundWorker when you got this error @Rachel? – jay_t55 Jul 03 '14 at 16:13
  • 2
    @Aeron These errors have nothing to do with a background worker, they're generic XAML Binding Errors. When you write a `{Binding }`, by default the `Source` is set to the `DataContext`, and the `Path` is set to the `Source`. When you write `ItemsSource="{Binding Source=Messages}`, you are changing the `Source` of that binding from the current `DataContext` to a string of `"Messages"`, and a string is nothing more than a character array. So you are binding your `ListView` to a character array of `{ M, e, s, s, a, g, e, s }`, and each `ListViewItem` has a `DataContext` of one of the characters – Rachel Jul 03 '14 at 16:20
  • "this.DataContext = this;", oh my... Why the f*** isn't this the default behavior??? – Camilo Terevinto Jul 20 '17 at 11:25
  • @CamiloTerevinto It's actually really poor design to write `this.DataContext = this` in most cases because the data is meant to be supplied by whoever is using the control. Hardcoding it like that breaks the separation of data and UI, and defeats one of WPF's biggest advantages of having "lookless controls". The only time it makes sense is for controls that are meant to define and use their own data only, or when testing. – Rachel Jul 20 '17 at 19:08
  • @Rachel I'm just creating a POC application for testing that has only 2 windows and need to do it as fast as possible, so I don't care about the design for this case. I'd in a real application, though – Camilo Terevinto Jul 20 '17 at 19:11
  • I had this exact problem, but the logic analysis applied, didn't help. In the end, it was because the class I was binding to was using public variables instead of public properties (ie public string Foo; with out a getter/setter). Simply adding `{get;set;}` fixed it instantly. – PandaWood Jun 15 '21 at 03:54
4

Unlike many .NET errors, these ones mean exactly what they say... all you have to do is to read them. Using this one as an example:

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

Somewhere in your XAML, you are trying to data bind a property named Sender to a TextBlock.Text property... this information is all in your error. However, it continues that the object being data bound is of type object and the object class does not have any property named Sender... therefore... error.

To fix it, find the TextBlock and the Binding and either swap the object with an instance of your class that does have the property named Sender, or alternatively use a property to bind to that is defined in the object class.

Judging by the number of these errors that you have, I have to assume that they are being caused by a Binding in an ItemTemplate, eg. you have the same error caused by each item of your collection.

Sheridan
  • 68,826
  • 24
  • 143
  • 183
2

If you use an ItemsSource property, it assumes you are passing in an IEnumerable. WPF will also, by default, present things as their type's name if it can't find anything else useful to do with something. Since string is an IEnumerable (of characters), the list item is passing the bound object's type's name into the ItemTemplate, as it's the only "reasonable" thing it can figure out to do. And, since the Char type obviously doesn't have Sender and Subject properties, your code goes boom.

As proof, compare the output of the below code and the hashcodes in your error messages.

foreach (char c in "Message") {
    Console.WriteLine(c.GetHashCode());
}

Instead of using a ListView, just use the stack panel with it's datasource equal to the message, and delete the enclosing controls:

<StackPanel DataSource={Binding Message} Orientation="Vertical" HorizontalAlignment="Stretch">
    <TextBlock x:Name="senderLabel" Text="{Binding Sender}" HorizontalAlignment="Stretch" TextTrimming="WordEllipsis" TextWrapping="Wrap" FontWeight="SemiBold" />
    <TextBlock x:Name="subjectLabel" Text="{Binding Subject}" HorizontalAlignment="Stretch" TextTrimming="WordEllipsis" TextWrapping="Wrap" />
</StackPanel>
Clever Neologism
  • 1,322
  • 8
  • 9
  • 1
    @Rachel's answer is a more correct explanation. I missed the "source" in the OP's binding, making it bind to the literal string "Message". My proposed solution, however is still correct. – Clever Neologism Jul 03 '14 at 16:26