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>
Best Answer
That is a DataBinding Error
Easiest way to read those is break it up by the colons/semi-colons, and read it backwards
1 tells you that there is a
Text
property causing the error2 tells you that the Text property is on a
<TextBlock>
element3 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 typeChar
5 tells you the actual problem with this: there is no property named
Sender
on the object of typeChar
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 yourMessage
class, and its clear thatMessage
is notChar
, its obvious that yourDataContext
for each item is wrong.Since it is set to a
Char
the most likely cause is you are binding to a string, and theDataContext
for each element is a character in that string.And sure enough,
ItemsSource="{Binding Source=Messages}
means you are changing the binding'sSource
property from the currentDataContext
to astring
. 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 thePath
property, then it will correctly readDataContext.Messages
instead, and should work.(The word
Path
here is optional, since if you don't specify a property name then the binding assumes it is the value for thePath
property)As a side note, I don't see you setting your
DataContext
anywhere on the form, and I don't see a publicMessages
property either.The
MainWindow
constructor should probably have a line of code that looks like this to set theDataContext
to itself :And you probably need a public property for your
ObservableCollection<Message> messages
so theListView
binding can find it :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 :
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 :)