在WPF中更新其中的元素时冻结列表框 [英] Freeze listbox while updating elements inside it in WPF
问题描述
大家好,
我正在建立一个真正的iskple聊天客户端,它基于MySQL数据库和PHP脚本。要下载消息,我调用一个PHP脚本,在页面上为我编写它们,然后我用 c得到结果c.DownloadString(mywebpage.php)
其中c是一个WebClient。
客户端的结构是一个代表单消息的类,名为 ChatMessage
和另一个类,从 ObservableColleciton< ChatMessage>
继承。然后,在窗口(包含ListBox)内,我立即收集集合类并将ListBox的ItemsSource属性分配给该对象。然后,通过使用 DispatcherTimer
,每隔10秒我调用集合类的刷新方法。
由于这必须处理网络,我决定使用另一个线程来调用刷新方法(我在 Window 中创建线程,并使用
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
App.Current.Dispatcher.Invoke(new Action(() => { this.Add(new ChatMessage(From, Body, Date)); }));
在方法结束时,我触发一个名为 RefreshedList的事件
At the end of the method, I fire an event called RefreshedList
App.Current.Dispatcher.Invoke(new Action(() => { RefreshedList(); }));
并且在窗口内有一个方法,如果满足某些条件,方法滚动 ListBox 到最后一项。
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.
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.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(); }));
}
当我清除列表时,ListBox会变空几毫秒,但这是可见的,当我向下滚动时,列表框闪烁,因为这个清晰,添加和滚动实际上是可见的。
我只需要冻结Listbox的刷新直到我添加了所有内容ObservableCollection的项目...
我还要补充说,如果方法被同步,则此问题不存在或它是不可见的......(显而易见,同步方法在没有Dispatcher的情况下执行)
你能帮我解决这个问题吗?
非常感谢!!
Lusvardi Gianmarco
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
推荐答案
请参阅我对Philippe Mori对问题的评论的评论。
您可以使用基于的数据源System.Collections.ObjectModel.ObservableCollection<& gt;
:
http://msdn.microsoft.com/en-us/library/ms668604%28v=vs.110%29.aspx [ ^ ]。
这个想法是:你修改的不是UI,而是修改数据,处理事件CollectionChanged
和PropertyChanged
负责UI更新。这种技术非常有用,因为这是UI中的推送技术: http://en.wikipedia。 org / wiki / Push_technology [ ^ ]。
你可以找到许多解释这种方法的手册:
http://msdn.microsoft.com/en-us/library/ms748365%28v=vs.110%29.aspx [< a href =http://msdn.microsoft.com/en-us/library/ms748365%28v=vs.110%29.aspxtarget =_ blanktitle =New Window> ^ ] ,
http://www.c-sharpcorner.com/UploadFile / e06010 / observablecollection-in-wpf [ ^ ],
使用ObservableCollection< T> [ ^ ],
http://stackoverflow.com/questions/21128666/how-to-bind-observablecollection-with-listbox-in-wpf [ ^ ](专门针对ListBox
)。
-SA
Please see my comment to the comment to the question by Philippe Mori.
You can use the data source based onSystem.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 eventsCollectionChanged
andPropertyChanged
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 forListBox
).
—SA
这篇关于在WPF中更新其中的元素时冻结列表框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!