I'm trying to add only items that are new to the ObservableCollection, so as not to create duplicates. Everything is in an infinite loop so I can add the new ones. The problem is that I can't figure out the best way to prevent duplicates in the list. To prevent the program from throwing me an exception for comparing items in an empty sheet. So I add them first and if they don't meet the condition, I remove them.
But then it flashes on the screen, e.g. in a table, as new items are added. So what to do? Thanks for any suggestions
bool help = true;
do
{
using (var client = new ImapClient())
{
using (var cancel = new CancellationTokenSource())
{
client.Connect(emailParser.ServerName, emailParser.Port, emailParser.isSSLuse,
cancel.Token);
//client.AuthenticationMechanisms.Remove("XOAUTH");
client.Authenticate(emailParser.Username, emailParser.Password, cancel.Token);
var inbox = client.Inbox;
inbox.Open(FolderAccess.ReadOnly, cancel.Token);
Console.WriteLine("Total messages: {0}", inbox.Count);
Console.WriteLine("Recent messages: {0}", inbox.Unread);
for (int i = 0; i < inbox.Count; i++)
{
var message = inbox.GetMessage(i, cancel.Token);
alerts.Add(message); // I Think the problem is here
for (int j = 0; j < alerts.Count-1; j++)
{
if (alerts[j].MessageId.Equals(message.MessageId))
{
alerts.Remove(message);
}
}
}
Console.WriteLine(alerts.Count);
alerts.Count();
}
client.Disconnect(true);
}
} while (help != false);
How about you not add the item unless the condition is met, instead of adding and removing later? If you do, your for loop becomes
for (int i = 0; i < inbox.Count; i++)
{
var message = inbox.GetMessage(i, cancel.Token);
if (!alerts.Any(x => x.MessageId.Equals(message.MessageId))
{
alerts.Add(message);
}
}
Use LINQ's Any method for enumerables which is safe against empty collections
Related
I am trying to do a mail app with Windows Forms C#. I only want to see the top 20 rows of my inbox.
Edit:
The code is working fine but only listing me 20 random emails in my inbox
I've tried this:
using (var client = new Pop3Client())
{
client.Connect("pop.gmail.com", 995, true);
client.Authenticate("mail", "passwrd");
for (int i = client.Count - 20; i < client.Count; i++)
{
var message = client.GetMessage(i);
Console.WriteLine("Subject: {0}", message.Subject);
txtBoxMails.AppendText("Subject: " + message.Subject + "\n");
}
client.Disconnect(true);
}
You can use GetMessages. It takes 2 parameters (int startIndex, int count). The index of the first message to get and how many messages.
An example without testing it.
var messages = client.GetMessages(0,20);
foreach (var item in messages)
{
Console.WriteLine(item.Subject);
}
you should use GetMessageCount instead of Count
var messageCount = client.GetMessageCount();
var lastMessageIndex = messageCount-20;
for (int i = messageCount; i > lastMessageIndex; i--)
{
//Do
}
I am new to C# and I have encountered an error stating that: InvalidArgument=Value of '2' is not valid for 'index'.
I want to set the items in checkedlistbox checked if there is a match in listbox.
Can anyone help me with this problem.
This the part of my code where the problems appear.
for (int i = 0; i < checklistbox.Items.Count; i++)
{
if (checklistbox.Items[i].ToString() == listbox.Items[i].ToString())
{
//Check only if they match!
checklistbox.SetItemChecked(i, true);
}
}
You just need to use nested for loop. Here is the code.
for (int i = 0; i < listbox.Items.Count; i++)
{
for (int j = 0; j < checkedlistbox.Items.Count; j++)
{
if (listbox.Items[i].ToString() == checkedlistbox.Items[j].ToString())
{
//Check only if they match!
checkedlistbox.SetItemChecked(i, true);
}
}
}
The reason you are getting this error is because you are looping through the count of checklistbox items. So, for example if there are 3 items in that array, and listbox only has 2 items, then on the third loop (when i = 2), you are trying to reference an item in the listbox array that does not exist.
Another way to do it would be like this:
foreach (var item in listbox.Items)
{
if (Array.Exists(checklistbox.Items, lbitem => lbitem.ToString() == item.ToString()))
{
//They match!
checklistbox[item].MarkAsChecked()
}
}
Update: answer updated to add MarkAsChecked() and loop through user inputted values held within checklist array.
This question already has answers here:
Thread parameters being changed
(2 answers)
Closed 5 years ago.
I am creating a file downloader in .NET which downloads an array of files from a server using Asynchronous tasks. However, even though I create the Task[] and returned string[] with the same length.
Here is my method:
public static string[] DownloadList(string[] urlArray, string[] toPathArray, string login = "", string pass = "", bool getExt = false)
{
Console.WriteLine("DownloadList({0}, {1}, {2}, {3}, {4})", urlArray, toPathArray, login, pass, getExt);
try {
returnedArray = new string[urlArray.Length];
Task[] taskArray = new Task[urlArray.Length];
for (int i = 0; i < urlArray.Length; i++)
{
Thread.Sleep(1000);
Console.WriteLine("i = {0}", i);
Task task = new Task(() => { returnedArray[i] = Download(urlArray[i], toPathArray[i], login, pass, getExt, true); });
task.Start();
taskArray[i] = task;
}
Task.WaitAll(taskArray);
Thread.Sleep(1000);
Console.WriteLine();
Console.WriteLine("Done! Press Enter to close.");
Console.ReadLine();
return returnedArray;
}
catch(Exception e)
{
Console.WriteLine();
Console.WriteLine(e.Message);
Console.ReadLine();
return null;
}
}
and the exception:
which points to this line:
I know it will be something daft that I missed, but I'm rattling my brain trying to figure it out. Thanks for the help in advance!
It looks like Access to Modified Closure problem.
Copy i to local variable:
for (int i = 0; i < urlArray.Length; i++)
{
int index = i;
Thread.Sleep(1000);
Console.WriteLine("i = {0}", index );
Task task = new Task(() => { returnedArray[index] = Download(urlArray[index], toPathArray[index], login, pass, getExt, true); });
task.Start();
taskArray[index] = task;
}
#Backs's answer is correct. Interestingly, in recent versions of .Net, if you use foreach, then the loop variable is closed over. So, you could:
foreach(var i in Enumerable.Range(0, urlArray.Length))
{
... new Task(() => { returnedArray[i] = ...
}
without needing to take a copy.
Looks like you are overshootinhg the array by one, because you count the length of the array in the cycle, and that's 10, while the array goes from 0 to 9.
for (int i = 0; i < urlArray.Length; i++)
Should be
for (int i = 0; i < urlArray.Length - 1; i++)
Rather than using .Purge(), is there a way to delete a defined number of messages from a queue?
I've tried setting up a MessageEnumerator and using .RemoveCurrrent after I've done whatever I need to do with the current message but it does not seem to work.
Thanks
public Message[] Get10(MessageQueue q)
{
int counter = 0;
int mCount = 0;
List<Message> ml = new List<Message>();
try
{
MessageEnumerator me = q.GetMessageEnumerator2();
while (me.MoveNext())
{
counter++;
}
if (counter > 10)
{
mCount = 10;
}
else
{
mCount = counter;
}
counter = 0;
me.Reset();
do
{
me.MoveNext();
counter++;
ml.Add(me.Current);
me.RemoveCurrent();
} while (counter < mCount);
}
catch (Exception x)
{
Console.WriteLine(x.Message);
}
Message[] m = ml.ToArray();
return m;
}
When you call RemoveCurrent(), the enumerator is moved to the next message. You do not have to call MoveNext() after calling RemoveCurrent().
Another approach you may try is something like the following:
List<Message> ml = new List<Message>();
int count = 0;
while( count < 10 ) {
ml.Add(me.RemoveCurrent());
++count;
}
In this case, you must be aware that RemoveCurrent will wait forever if there are no messages left in the queue. If that is not what you want, you may want to use the RemoveCurrent(TimeSpan timeout) overload and catch the MessageQueueException that get thrown in case of timeout. The MessageQueueException class has a MessageQueueErrorCode property that is set to MessageQueueErrorCode.IOTimeout if a timeout has expired.
Or also (this will get at most 10 messages: the loop will exit if the message count in your queue drops to zero):
List<Message> ml = new List<Message>();
int count = 0;
while( me.MoveNext() && count < 10 ) {
ml.Add(queue.ReceiveById(me.Current.Id));
++count;
}
I have the following code.
I am trying to insert values into a listbox, and then be able to resort the values by alphabetical order and re display them in the same listbox. For some reason code doesn't work (no errors - just when i push the button the listbox clears)
protected void sortButton_Click(object sender, ImageClickEventArgs e)
{
string[] movieArray = new string [cartListBox.Items.Count];
for (int i = 0; i < cartListBox.Items.Count; i++)
{
movieArray[i] = cartListBox.Items[i].ToString();
}
Array.Sort(movieArray);
cartListBox.Items.Clear();
for (int i = 0; i < cartListBox.Items.Count; i++)
{
cartListBox.Items.Add(movieArray[i].ToString());
}
}
I think problem is in last loop.
Do that like follows:
cartListBox.Items.Clear();
for (int i = 0; i < movieArray.Length; i++)
{
cartListBox.Items.Add(movieArray[i].ToString());
}
When you are clearing cartListBox.Items.Clear();, it should not be taken for loop counter like, for (int i = 0; i < cartListBox.Items.Count; i++)
cartListBox.Items.Count was creating problem.
You can avoid all that looping, and your bug, by doing this in a more modern way:
var items = cartListBox.Items
.Select(item => item.ToString())
.OrderBy(x => x);
cartListBox.Items.Clear();
cartListBox.Items.AddRange(items);
cartListBox.Items.Count // is 0 length
you are doing in the previous step:
cartListBox.Items.Clear();
To add movieArray to listbox use AddRange
carListBox.Items.AddRange(movieArray);
To sort just set sorted =true
carListBox.Sorted=true;
Complete code is below
carListBox.Items.AddRange(movieArray);
carListBox.Sorted=true;