Click here to Skip to main content
15,895,746 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi everybody,

I'm building a really iskple chat client which is based on a MySQL db and a PHP script. To download the messages, I call a PHP script which writes them for me on a page and then I get the results with c.DownloadString("mywebpage.php") where c is a WebClient.

The client is structured with a class which represents a single message called ChatMessage and another class, which inherits from ObservableColleciton<ChatMessage>. Then, inside a window (which contains a ListBox), I instantate the collection class and assign the ListBox's ItemsSource property to that object. Then, by using a DispatcherTimer, every 10 seconds I call the Refresh method of the collection class.

As this has to deal with web, I decided to use another thread to call the Refresh method (I create the thread inside the Window) and to add items to the colleciton by using
C#
App.Current.Dispatcher.Invoke(new Action(() => { this.Add(new ChatMessage(From, Body, Date)); }));


At the end of the method, I fire an event called RefreshedList
C#
App.Current.Dispatcher.Invoke(new Action(() => { RefreshedList(); }));


and there is a method, inside the Window which is called and if some conditions are met, the method Scrolls the ListBox to the last item.
C#
if (!(this.IsActive == true && this.lstChat.IsFocused == true))
            {
                this.lstChat.ScrollIntoView(ch.Last());
            }


The problem is that at the beginning of the Refresh method I delete all the items in the collection to add the other ones:

C#
c.UseDefaultCredentials = true;
                            c.Credentials = Settings.Auth;
                            string t = c.DownloadString(Settings.ChatRead);
                            string[] Content = t.Split('\x6');
                            App.Current.Dispatcher.Invoke(new Action(() => { this.Clear(); }));
                            foreach (string s in Content)
                            {
                                try
                                {
                                    if (String.IsNullOrWhiteSpace(s))
                                        continue;
                                    Regex Finder = new Regex(@"\[[^\]]*]");
                                    var Matches = Finder.Matches(s);
                                    string From = Matches[0].Value.Substring(1, Matches[0].Value.Length - 2);
                                    string Date = Matches[1].Value.Substring(1, Matches[1].Value.Length - 2);
                                    string Body = s.Substring(Matches[1].Index + Date.Length + 2);
                                    App.Current.Dispatcher.Invoke(new Action(() => { this.Add(new ChatMessage(From, Body, Date)); }));
                                }
                                catch (Exception)
                                {
                                }
                            }
                            if (RefreshedList != null)
                            {
                                App.Current.Dispatcher.Invoke(new Action(() => { RefreshedList(); }));
                            }


and when I clear the list, the ListBox becomes empty for a few milliseconds, but this is visible and, when I scroll down, the listbox "blinks" because this clear, adding and scrolling is actually visible.

I just need to freeze Listbox's refresh just until I have added all the items to the ObservableCollection...

I have also to add that if the method is called synchronously, this problem does not exist or it is not visible... (Obiviously, the synchronous method is executed without the Dispatcher)

Could you please help me with that problem?

Thanks a lot!!

Lusvardi Gianmarco
Posted
Comments
Afzaal Ahmad Zeeshan 11-Jan-15 17:49pm    
What actually do you mean to freeze the listbox? Did you try to disable the list, or try not-to-do-anything with the listbox?
Philippe Mori 11-Jan-15 20:20pm    
For such an application, you should really only handle changes to begin with. Thus, you should only add new items instead of clearing the list and adding items again. Doing that would greatly improve user experience and performance as you would only have to query for added item instead of the whole list.
Sergey Alexandrovich Kryukov 11-Jan-15 22:38pm    
Even better, OP should define a data source implementing System.Collections.ObjectModel.ObservableCollection<>.
Than manipulation on the ListBox items could be reduced to manipulation with data of the collection.
Please see Solution 1.
—SA
LLLLGGGG 12-Jan-15 11:10am    
Thankx for your comment, I have thought about the same solution this morning at school while I was talking with a friend of mine...

1 solution

Please see my comment to the comment to the question by Philippe Mori.
You can use the data source based on System.Collections.ObjectModel.ObservableCollection<>:
http://msdn.microsoft.com/en-us/library/ms668604%28v=vs.110%29.aspx[^].

The idea is: you modify not UI but data, and handling of the events CollectionChanged and PropertyChanged takes care of UI update. This technique is very beneficial, because this is the push technology in UI: http://en.wikipedia.org/wiki/Push_technology[^].

You can find a number of manuals explaining this approach:
http://msdn.microsoft.com/en-us/library/ms748365%28v=vs.110%29.aspx[^],
http://www.c-sharpcorner.com/UploadFile/e06010/observablecollection-in-wpf[^],
Working with ObservableCollection<T>[^],
http://stackoverflow.com/questions/21128666/how-to-bind-observablecollection-with-listbox-in-wpf[^] (specifically for ListBox).

—SA
 
Share this answer
 
Comments
LLLLGGGG 12-Jan-15 11:09am    
Thanks a lot for your solution. I will dig through the topic, I didn't know the push technology...

LG
Sergey Alexandrovich Kryukov 12-Jan-15 14:18pm    
You are very welcome.
Good luck, call again.
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900