So I have a listbox that shows the subject of an email (I use the chilkat imap client) when I select 开发者_C百科the subject of an email I want to show the message body in a textbox but i cant figure out how to do it, obviusly i use the listbox selectindexchanaged event but how would i go about it
Code So Far
// Create an object, connect to the IMAP server, login,
// and select a mailbox.
Chilkat.Imap imap = new Chilkat.Imap();
imap.UnlockComponent("UnlockCode");
imap.Connect("Imap URL");
imap.Login("email address", "password");
imap.SelectMailbox("Inbox");
// Get a message set containing all the message IDs
// in the selected mailbox.
Chilkat.MessageSet msgSet;
msgSet = imap.Search("ALL", true);
// Fetch all the mail into a bundle object.
Chilkat.EmailBundle bundle = new Chilkat.EmailBundle();
bundle = imap.FetchBundle(msgSet);
// Loop over the bundle and display the From and Subject.
Chilkat.Email email;
int i;
for (i = 0; i < bundle.MessageCount - 1; i++)
{
email = bundle.GetEmail(i);
listBox1.Items.Add(email.From + ": " + email.Subject);
textBox1.Text = email.Body ;
}
// Save the email to an XML file
bundle.SaveXml("bundle.xml");
// Disconnect from the IMAP server.
// This example leaves the email on the IMAP server.
imap.Disconnect();
}
}
thanks in advance
Assuming that the email indexes stay the same (I think the safest way to make sure of that would be to cache the fetched bundle in the form), I'd change to using a ListView
instead of the ListBox
and then I'd add the indexes to the list, either as a separate column or in the Tag
of the items.
After you'd set up the ListView
to look as you need it to look (ListView.View = View.Details;
and ListView.MultiSelect = false;
are probably the main ones) instead of:
listBox1.Items.Add(email.From + ": " + email.Subject);
you could do something like (if you do it the Tag
way, which is slightly easier but some people think is bad):
listView1.Items.Add(email.From + ": " + email.Subject).Tag = i;
And then when the user selects a subject in the list, as you say, you handle the ListView.SelectedIndexChanged
event and then just do something like:
if(ListView.SelectedItems.Count > 0)
{
textBox1.Text = bundle.GetEmail((int)ListView.SelectedItems[0].Tag).Body;
}
Or if you're sure you only ever want to get out the text from the emails, you could insert the texts into the tags instead of the indexes.
In your xaml set up the listboxes to bind to the properties you'd like, and set up event handlers for when the selection changes.
<StackPanel>
<ListBox Name="listbox1" SelectionChanged="listbox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=From}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Name="listbox2" SelectionChanged="listbox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Subject}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox Name="textbox1"></TextBox>
</StackPanel>
Then in your code behind. bind the listboxes to a list of the email objects.
listbox1.ItemsSource = emails;
listbox2.ItemsSource = emails;
finally you need to handle the event from the listboxes.
private void listbox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox listbox = (ListBox)sender;
foreach (Email email in listbox.SelectedItems)
{
textbox1.Text = email.Body;
}
}
Please note this code is not tested.
Your issue is not with the email but with how you are displaying items in your form. You are trying to do things in a winforms way, which is fine for winforms (kind of) but really is pointless and code-heavy in WPF. You should do some reading about MVVM (plenty of questions here on the subject).
Here's a demo showing what you want to do using only a few lines of code that takes advantage of the binding infrastructure of WPF. You can create a new WPF app and copypaste the few lines (change my namespace and class names to match the app you create!) and see it in action.
There is one window. I'm simulating emails here; you'd get your emails and dump them in the collection:
public partial class MainWindow : Window
{
public ObservableCollection<FakeEmail> Emails { get; private set; }
public MainWindow()
{
Emails = new ObservableCollection<FakeEmail>();
// simulates emails being received; you would popoulate with valid emails IRL
Emails.Add(new FakeEmail
{ From = "herp", Subject = "derp", Message = "herp derp" });
Emails.Add(new FakeEmail
{ From = "foo", Subject = "bar", Message = "foo bar" });
Emails.Add(new FakeEmail
{ From = "Binding", Subject = "Rocks", Message = "Binding rocks" });
InitializeComponent();
}
}
/// <summary>
/// I don't have your libraries
/// </summary>
public sealed class FakeEmail
{
public string From { get; set; }
public string Subject { get; set; }
public string Message { get; set; }
}
I've added an ObservableCollection of type FakeEmail to the window. OCs work well with binds, as the collection notifies binds when elements are added or removed.
Next, the window. Please note, I'm not showing the <Window
definition here, but I have named the window emailClient
!
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox
x:Name="emailList"
ItemsSource="{Binding Emails, ElementName=emailClient}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock
Text="{Binding From}" />
<TextBlock
Text="{Binding Subject}"
TextWrapping="NoWrap"
TextTrimming="CharacterEllipsis" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock
Grid.Column="1"
Text="{Binding SelectedValue.Message, ElementName=emailList, FallbackValue='Select an email pls'}" />
</Grid>
Some of the finer notes: The ListBox's ItemsSource is bound to the ObservableCollection I defined on the window. The ListBox will listen for items coming and going in that collection, and use the DataTemplate to display UI for each item in the colleciton.
For each FakeEmail the ItemTemplate finds, it creates a new instance of the DataTemplate and contents, and sets the DataContext of the template to the FakeEmail instance. That means, within the DataTemplate I can simply bind against the properties of a FakeEmail instance and everything gets wired up at runtime.
The ListBox has a property called SelectedValue, which I can use to show the email message. When you select an item in the ListBox, SelectedValue is the instance from ItemsSource that is the DataContext of the DataTemplate; that which is currently displayed in that item in the UI. So, in order to show the currently selected email's message, I just need to bind against the ItemSource's SelectedValue's Message property, since SelectedValue will be the currently selected email.
And that's it. No listening, no "\r\n" BS. A couple binds and an Observable collection.
精彩评论