Hi everyboy I have some problem with Multi Thread and ListView Update:
I want to list running process by name in a Listview, and removing when this process close. But my code just adding a new process and dont remove when the process close. I am a beginner user in C#. Thank you.
*** I dont want to use listview.Clear() cause Im going to make a bot with multi client
Here's my code:
bool status = true;
int[] PID = new int[10];
Memory Mem = new Memory();
private void startChecking()
{
while (status)
{
try
{
int count = 0;
Process[] processes = Process.GetProcessesByName("notepad");
if (processes.Length > 0)
{
if (listAccount.Items.Count < processes.Length)
{
foreach (Process process in processes)
{
if (listAccount.Items.Count < processes.Length && PID[count] != process.Id)
{
Mem.SetTitle(process.MainWindowHandle, "Cyber Auto - " + count.ToString());
AddItemNew(process.MainWindowTitle);
PID[count] = process.Id;
}
count++;
}
}
else if (listAccount.Items.Count < processes.Length)
{
}
}
Thread.Sleep(1000);
}
catch (Exception ex)
{
MessageBox.Show("Somethine went wrong : " + ex.ToString());
}
}
}
Here is my AddItemNew / RemoveItem methods:
private delegate void dlgAddItemNew(string i);
private void AddItemNew(string i)
{
if (this.listAccount.InvokeRequired)
{
this.Invoke(new dlgAddItemNew(AddItemNew), i);
}
else
{
ListViewItem accountAdd = new ListViewItem(i);
accountAdd.SubItems.Add("0");
accountAdd.SubItems.Add("0");
accountAdd.SubItems.Add("0");
accountAdd.SubItems.Add("0");
this.listAccount.Items.Add(accountAdd);
}
}
private delegate void dlgRemoveItem(int i);
private void RemoveItem(int i)
{
if (this.listAccount.InvokeRequired)
{
this.Invoke(new dlgRemoveItem(RemoveItem), i);
}
else
{
this.listAccount.Items[i].Remove();
}
}
P/S : Sorry If my Enlish is not good....
If you want to check at periodic interval, then you can clear the ListView before populating it again. (This is what Captain0 meant in his comments above)
I have modified your code a bit and I can see it working when I open/close instance of notepad, it update the count, No need for separate add/remove items (unless you had to something different in opening & closing of notepad process)
private void startChecking()
{
while (status)
{
try
{
Process[] processes = Process.GetProcessesByName("notepad");
UpdateListView(processes.Count());
Thread.Sleep(2000);
}
catch (Exception ex)
{
MessageBox.Show("Somethine went wrong : " + ex.ToString());
status = false;
}
}
}
private void UpdateListView(int processCount)
{
if (listView1.InvokeRequired)
{
Action action = () => UpdateListView(processCount);
Invoke(action);
}
else
{
listView1.Items.Clear(); // Clearing the List view before adding them again
for (int i = 0; i < processCount; i++)
{
ListViewItem accountAdd = new ListViewItem(i.ToString());
listView1.Items.Add(accountAdd);
}
}
}
Related
I am implementing a single Producer/Consumer Pattern using BlockingCollection.
When i click 'c' from keyboard i want to cancel the operation using CancellationToken.
The strange thing is that if i press 'c' as fast as i can after i run the program, the program listen to the event.
If i click 'c' later lets say at 45000th iteration the program doesnt react.
I have a for loop that populates the producer.
for (int i = 0; i < 50000; i++)
{
logger.AddToQueue("Number with flush " + i, true);
}
logger.DataItems.CompleteAdding();
At the constructor of logger i call this method:
private Task t;
public void KeyPress()
{
t = Task.Run(() =>
{
if (Console.ReadKey(true).KeyChar == 'c')
{
cts.Cancel();
}
});
}
I dont know if the error is relevant to the other methods but i will post them just in case:
The addToQueue (Producer):
public void AddToQueue(String text, bool isFlushOn) {
Consumer(isFlushOn);
try {
_dataItems.TryAdd(new LogLine() { Text = text, Timestamp = DateTime.Now }, 0, ct);
} catch (OperationCanceledException) {
_dataItems.CompleteAdding();
}
}
and the consumer:
Task task = null;
public void Consumer(bool isStopWithFlushOn)
{
if (task == null)
{
task = Task.Run(() =>
{
while (!_dataItems.IsCompleted) {
try {
LogLine data = null;
if (!_dataItems.TryTake(out data, 5, ct)) {
Console.WriteLine(" Take Blocked");
} else {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(data.Timestamp.ToString("yyyy-MM-dd HH:mm:ss:fff"));
stringBuilder.Append("\t");
stringBuilder.Append(data.LineText());
stringBuilder.Append("\t");
_writer.WriteLine(stringBuilder.ToString());
Console.WriteLine(" Take:{0}", data.Text);
}
} catch (OperationCanceledException) {
if (isStopWithFlushOn) {
Console.WriteLine("Canceled with flush.");
foreach (var dataItem in _dataItems.GetConsumingEnumerable()) {
Console.WriteLine("Canceled Take:{0}", dataItem.Text);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(dataItem.Timestamp.ToString("yyyy-MM-dd HH:mm:ss:fff"));
stringBuilder.Append("\t");
stringBuilder.Append("Number with flush " + dataItem.LineText());
stringBuilder.Append("\t");
_writer.WriteLine(stringBuilder.ToString());
Thread.SpinWait(500000);
}
} else {
Console.WriteLine("Canceled without flush.");
break;
}
}
}
Console.WriteLine("\r\nNo more items to take.");
});
}
}
I have a function called getMessages that can be called by a Button click (using the RelayCommand trigger) or that is called in a timer every 15s.
The desired behavior is:
webservice > deserialize answer > system notification > updatelistview > insert localDB
But when the function is called by the timer the updatelistview is not done. Why does this happen if the function is the same and works perfectly in the button command?
CODE:
// Get messages for the logged in user
public async void getMessages()
{
try
{
List<FriendGetMessage> msg = new List<FriendGetMessage>();
var response = await CommunicationWebServices.GetCHAT("users/" + au.idUser + "/get", au.token);
if (response.StatusCode == HttpStatusCode.OK) // If there are messages for me.
{
var aux = await response.Content.ReadAsStringAsync();
IEnumerable<FriendGetMessage> result = JsonConvert.DeserializeObject<IEnumerable<FriendGetMessage>>(aux);
if (result != null)
{
foreach (var m in result)
{
msg.Add(m);
}
//MsgList=msg;
foreach (var f in Friends)
{
if (f.msg == null || f.msg.Count() == 0)
{
f.msg = new ObservableCollection<Messages>();
}
foreach (var mess in msg)
{
if (mess.idUser == f.idUser)
{
Messages mm = new Messages();
mm.received = mess.message;
mm.timestamp = "Received " + mess.serverTimestamp;
mm.align = "Right";
// Add to the friend list.
f.msg.Add(mm);
// Add to Local DB
InsertMessage(null, au.idUser.ToString(), f.idUser, mess.message, mess.serverTimestamp);
var notification = new System.Windows.Forms.NotifyIcon()
{
Visible = true,
Icon = System.Drawing.SystemIcons.Information,
BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info,
BalloonTipTitle = "New Message from " + f.name,
BalloonTipText = "Message: " + mess.message,
};
// Display for 5 seconds.
notification.ShowBalloonTip(5);
// The notification should be disposed when you don't need it anymore,
// but doing so will immediately close the balloon if it's visible.
notification.Dispose();
}
}
}
counterChat = 1; // resets the counter
}
}
else {
counterChat = counterChat * 2;
}
//var sql = "select * from chat";
//var respo = GetFromDatabase(sql);
OnPropertyChanged("Friends");
}
catch (Exception e)
{
MessageBox.Show("GetMessages: " + e);
Debug.WriteLine("{0} Exception caught.", e);
}
}
CODE TIMER:
public void chatUpdate()
{
_timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
}
public void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
getMessages();
OnPropertyChanged("Friends");
incChat = 0;
}
}
ADDED - I've also tried this and didn't worked (it seems that is some kind of concurrency problem to the ObservableCollection called Friends (is a friendslist) each friend has an ObservableCollection of messages (is a chat))
public void chatUpdate()
{
_timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
}
public async void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
Application.Current.Dispatcher.Invoke((Action)async delegate { await getMessages(); });
incChat = 0;
}
}
Best regards,
I think you need to make the timer handler be an async method as follows:
public async void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
await getMessages();
OnPropertyChanged("Friends");
incChat = 0;
}
}
This way OnPropertyChanged("Friends") is guaranteed to fire after the work in getMessages is done.
The methods need to change to:
DispatcherTimer _timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
public async void timerchat_Tick(object sender, EventArgs e)
{
//...
await getMessages();
//...
}
public async Task getMessages()
{
try
{
// ... your code here
string result = await response.Content.ReadAsStringAsync();
// .... rest of your code
}
catch (Exception e)
{
MessageBox.Show("GetMessages: " + e);
}
}
It is solved. The problem was in my ViewModels I was opening multiple threads and sometimes the right one would update the UI and sometimes no.
Thanks for all the answers.
I registered my application on ".mp3" Files.
My App is a Single Instance Application.
Goal: when user open a mp3 file if myApp isn't running Is start running and show the selected files count in explorer else show the app window and show the selected files count in explorer (Just Once). Then Call a function in application form that add the mylist items to listbox1.
2nd Problem: the results I get when call mylist in application form is different than the results in myfunc() why it's different?
I added commented lines thought may help!
I think my Question is clear! if it's not tell me to make it clear.
[STAThread]
static void Main(string[] args)
{
if (SingleApplicationDetector.IsRunning())
{// These Codes Runs n times!
myfunc(); // But I want this Code Run just one time!
return;
}
//myfunc();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
SingleApplicationDetector.Close();
}
public static class SingleApplicationDetector
{
public static bool IsRunning()
{
string guid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();
var semaphoreName = #"Global\" + guid;
try
{
__semaphore = Semaphore.OpenExisting(semaphoreName, SemaphoreRights.Synchronize);
Close();
return true;
}
catch (Exception ex)
{
__semaphore = new Semaphore(0, 1, semaphoreName);
return false;
}
}
public static void Close()
{
if (__semaphore != null)
{
__semaphore.Close();
__semaphore = null;
}
}
private static Semaphore __semaphore;
}
public static List<string> mylist = new List<string>();
public static System.Diagnostics.Process[] p = System.Diagnostics.Process.GetProcessesByName("ACE Music Player");
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
public static void myfunc()
{
if (!File.Exists("1.txt")) // I somehow achieved my goal by using this but it does not work very well for large number of files, and of course there should be a better solution!
{
File.WriteAllText("1.txt", "testing");
if (p.Length > 0)
{
for (int i = 0; i < p.Length; i++)
{
SetForegroundWindow(p[i].MainWindowHandle);
}
}
// MessageBox.Show("Running");
{
try
{
string filename;
List<string> selected = new List<string>();
foreach (SHDocVw.InternetExplorer window in new SHDocVw.ShellWindows())
{
filename = Path.GetFileNameWithoutExtension(window.FullName).ToLower();
if (filename.ToLowerInvariant() == "explorer")
{
Shell32.FolderItems items = ((Shell32.IShellFolderViewDual2)window.Document).SelectedItems();
foreach (Shell32.FolderItem item in items)
{
if (item.Path.StartsWith(System.Environment.CurrentDirectory))
{
selected.Add(item.Path);
// mylist.Add(item.Path);
// MessageBox.Show("FilePath: " + selected[selected.Count - 1]);
}
/*
MessageBox.Show(Environment.GetCommandLineArgs().GetValue(1).ToString());
int myint = Environment.GetCommandLineArgs().GetValue(1).ToString().LastIndexOf(".");
MessageBox.Show(myint.ToString());
string str = Environment.GetCommandLineArgs().GetValue(1).ToString().Remove(myint);
MessageBox.Show(str);
if (item.Path.StartsWith(str))
{
MessageBox.Show(item.Path);
selected.Add(item.Path);
}
*/
// selected.Add(item.Path);
}
}
}
mylist.AddRange(selected);
// Thread.Sleep(TimeSpan.FromMilliseconds(3000));
//TotalLines("");
// if (!File.Exists("1.txt"))
// {
//// File.WriteAllLines("1.txt", mylist.ToArray());
// test();
//// File.WriteAllText("2.txt", File.ReadAllText("1.txt"));
//// File.Delete("1.txt");
MessageBox.Show(mylist.Count.ToString()+": "+mylist[mylist.Count - 1]);
// Thread.Sleep(TimeSpan.FromMilliseconds(3000));
// File.WriteAllText("3.txt", "Done!");
// Thread.Sleep(500);
File.Delete("1.txt");
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
}
}
}
Update=>
This is what I want to do:
Player Verb
Windows SDK Download Page
I will update this post when I completely handled my problem!
but at least & finally I got the solution I was looking for.
Hope this thread help others too :)
My current Problem is that sample is written in C++, and I can't understand it well till now!
and I need to mix it with my application(written in C#). If it's possible!!??
Single app example
bool createdNew;
Mutex m = new Mutex(true, "YOURAPPNAME", out createdNew);
if (!createdNew)
{
MessageBox.Show("already running!");
return;
}
public void processloader(object temp)
{
Process[] processes = null;
try
{
processes = Process.GetProcesses();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
Application.Exit();
return;
}
listView1.BeginUpdate();
listView1.Clear();
int threadscount = 0;
listView1.Items.Clear();
foreach (Process p in processes)
{
try
{
string[] prcdetails = new string[] { p.ProcessName, p.Id.ToString(), p.StartTime.ToShortTimeString(), p.PriorityClass.ToString(), (p.WorkingSet64 / 1048576).ToString() + "Mb", p.Threads.Count.ToString() };
ListViewItem proc = new ListViewItem(prcdetails);
listView1.Items.Add(proc);
threadscount += p.Threads.Count;
}
catch { Console.WriteLine(p); }
}
statusBar1.Panels[0].Text = "Processes : " + processes.Length.ToString();
statusBar1.Panels[1].Text = "Threads : " + (threadscount + 1).ToString();
listView1.EndUpdate();
listView1.Refresh();
}
here is the refreher block i call this function every second by using System.threading.timer(). i need a solution like original taskmanager refreshing functionality can anyone help for this? please provide some sample codes. thanks in advance!
use the below link helpful for your problem:
http://social.msdn.microsoft.com/Forums/eu/csharplanguage/thread/f8cb71ef-aba6-42f6-a462-533bca201d9e
My error
Cross-thread operation not
valid: Control 'MailTree' accessed
from a thread other than the thread it
was created on.
with my code
My idea is when SaveMail method has finish store 1 mes then add this mes to listview.
private delegate int SaveMailDelegate(ImapX.Message mes);
public int SaveMail(ImapX.Message mess)
{
if (!File.Exists("D:\\" + Username + "\\" + MailTree.SelectedNode.Text + "\\" + mes.MessageUid.ToString() + ".eml"))
{
mess.Process();
mess.SaveAsEmlToFile("D:\\" + Username + "\\" + MailTree.SelectedNode.Text + "\\", mes.MessageUid.ToString()); //Store messages to a Location
}
// mes.MessageUid=mess.MessageUid;
return 1;
}
Mime EncodingMail(string NodeName,string focusitem)
{
Mime m = new Mime();
m=Mime.Parse("D:\\" + Username+ "\\"+NodeName+"\\"+focusitem+".eml");
return m;
}
private void AddMesToMailList()
{
ListViewItem item = new ListViewItem();
Mime m = EncodingMail(MailTree.SelectedNode.Text, mes);
item.Text = mes.MessageUid.ToString();
item.SubItems.Add(m.MainEntity.Subject);
ReturnMime(m);
if (mailfromname != null)
item.SubItems.Add(mailfromname);
else item.SubItems.Add(mailfrom);
item.SubItems.Add(m.MainEntity.Date.ToString());
item.SubItems.Add(mailfrom);
MailList.Items.Add(item);
}
private void SaveMailDone(IAsyncResult iar)
{
SaveMailDelegate del = iar.AsyncState as SaveMailDelegate;
if (del != null)
{
int result = del.EndInvoke(iar);
AddMesToMailList();
}
}
private void MailTree_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
{
MailList.Items.Clear();
for (int i = 0; i < client.Folders.Count; i++)
{
(ContextMenuListView.Items[1] as ToolStripMenuItem).DropDownItems[i].Click += new EventHandler(MainForm_Click);
}
if (MailTree.SelectedNode.Text == Username)
{
webBrowser1.Visible = false;//webBrowser1.DocumentText = "Hello Baby";
AttachmentList.Visible = false;
groupBox1.Visible = false;
}
else
{
webBrowser1.Visible = true;
groupBox1.Visible = true;
try
{
messages = client.Folders[MailTree.SelectedNode.Text].Search("ALL", false); // Search mail in your choossen Folder
AmoutOfMail = messages.Count(); //Amout of Mail in this Folder
for (int i = 0; i < AmoutOfMail; i++)
{
mes=messages[i];
SaveMailDelegate del = new SaveMailDelegate(this.SaveMail);
del.BeginInvoke(mes, new AsyncCallback(this.SaveMailDone), del);
}
}
catch (Exception)
{ }
}
}
You cannot directly access a control from another thread, you will have to invoke it.
private delegate void ControlCallback(string s);
public void CallControlMethod(string text)
{
if (control.InvokeRequired)
{
ControlCallback call = new ControlCallback((s) =>
{
// do control stuff
});
control.Invoke(call, new object[] { text });
}
else
{
// do control stuff
}
}
you can't access the UI on a different thread than what it was created on. From inside your secondary thread (the one that runs your callback handler) you will need to call Form.BeginInvoke to register a method that will be run on the UI thread. From that method you can update your UI controls
I think AddMesToMailList() is trying to modify the view elements but it is on a wrong thread.
Try something like this
void AddMesToMailList()
{
if (this.InvokeRequired)
{
this.BeginInvoke(new Action(AddMesToMailList));
return;
}
// do stuff that original AddMesToMailList() did.
}
EDIT:
SaveMail is a little complicated as it has a return value but you can try this
public int SaveMail(ImapX.Message mess)
{
if(this.InvokeRequired)
{
return (int) this.Invoke(
new Func<ImapX.Message, int>( m => SaveMail(mess)) );
}
else
{
if (!File.Exists(#"D:\" + Username + "\\" + MailTree.SelectedNode.Text + "\\" + mes.MessageUid.ToString() + ".eml"))
{
mess.Process();
mess.SaveAsEmlToFile(#"D:\" + Username + "\\" + MailTree.SelectedNode.Text + "\\", mes.MessageUid.ToString()); //Store messages to a Location
}
// mes.MessageUid=mess.MessageUid;
return 1;
}
}