Reputation: 331
I am making a email client for work and I can't get the observable collection to bind to my listview in the correct way. Please, advise as I can't find my exact problem online
C#
public partial class Mail : UserControl
{
ObservableCollection<GetMails> BindMe = new ObservableCollection<GetMails>();
public Mail()
{
InitializeComponent();
}
private void Grid_Loaded_1(object sender, RoutedEventArgs e)
{
BindMe = FetchAllHeaders(server, port, false, username, password);
lstMail.ItemsSource = BindMe.ToList();
}
private ObservableCollection<GetMails> FetchAllHeaders(string hostname, int port, bool useSsl, string username, string password)
{
// The client disconnects from the server when being disposed
using (Pop3Client client = new Pop3Client())
{
GetMails gm = new GetMails();
// Connect to the server
client.Connect(hostname, port, useSsl);
// Authenticate ourselves towards the server
client.Authenticate(username, password);
// Get the number of messages in the inbox
int messageCount = client.GetMessageCount();
// We want to download all messages
ObservableCollection<GetMails> getHeaders = new ObservableCollection<GetMails>();
// Messages are numbered in the interval: [1, messageCount]
// Ergo: message numbers are 1-based.
// Most servers give the latest message the highest number
for (int i = messageCount; i > 0; i--)
{
MessageHeader headers = client.GetMessageHeaders(i);
RfcMailAddress from = headers.From;
Message message = client.GetMessage(i);
gm.Header = client.GetMessageHeaders(i).Subject;
gm.From = from.MailAddress.ToString();
int count = 0;
foreach (MessagePart attachment in message.FindAllAttachments())
{
count++;
}
gm.NumberAttach = count;
getHeaders.Add(gm);
}
// Now return the fetched messages
return getHeaders;
}
}
}
XAML
<UserControl x:Class="VeriMail.Mail"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Loaded="Grid_Loaded_1" Margin="0,0,-132,0">
<ListView x:Name="lstMail" Height="399" VerticalAlignment="Top" Margin="0,0,-67,-99" ScrollViewer.HorizontalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.CanContentScroll="True">
<ListView.View>
<GridView>
<GridViewColumn Width="140" Header="Subject" />
<GridViewColumn Width="140" Header="From" />
<GridViewColumn Width="140" Header="Number of Attachments"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
The output I get when I do it like this is just VeriMail.GetMail all over
If I change the gridview to this:
<GridViewColumn Width="140" Header="Subject" DisplayMemberBinding="{Binding Header}"/>
<GridViewColumn Width="140" Header="From" DisplayMemberBinding="{Binding From}"/>
<GridViewColumn Width="140" Header="Number of Attachments" DisplayMemberBinding="{Binding NumberAttach}"/>
Then the output changes to the information I want but it copies one email the last one inserted into the observable collection.
Upvotes: 0
Views: 1429
Reputation: 2574
UPDATE: The problem is when you call ToList
the collection is copied and won't reflect changes in future. Remove that method call and it should work.
However it's better to bind ItemsSource
in XAML than in code behind:
<ListView x:Name="lstMail" ItemsSource="{Binding BindMe, RelativeSource={RelativeSource AncestorType=UserControl}}" Height="399" VerticalAlignment="Top" Margin="0,0,-67,-99" ScrollViewer.HorizontalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.CanContentScroll="True">
<ListView.View>
<GridView>
<GridViewColumn Width="140" Header="Subject" />
<GridViewColumn Width="140" Header="From" />
<GridViewColumn Width="140" Header="Number of Attachments"/>
</GridView>
</ListView.View>
</ListView>
And also not change BindMe
collection reference itself in FetchAllHeaders()
, but instead modify it's contents. Otherwise the binding won't work because the reference is again changed.
Upvotes: 1
Reputation: 2159
As mentioned in another answer, its a usual practice to bind in the XAML (e.g. using the MVVM pattern). If you had done this, you may have found the bug...
lstMail.ItemsSource = BindMe.ToList();
When you call ToList()
you create a brand new List<GetMails>
containing the contents of the observable collection. When you add a new item, the list doesn't change - it's a copy and knows nothing about the original collection.
Try
lstMail.ItemsSource = BindMe;
and this should fix your problem.
Upvotes: 1
Reputation: 1439
lstMail.ItemsSource = BindMe.ToList();
should be
lstMail.ItemsSource = BindMe;
Binding to a list is different than binding to an ObservableCollection. Observable collection is the object to use for binding because it implements ICollectionChanged. List does not.
Upvotes: 0