I have some nice animations that show a fade-in when I add an item to my listbox. I thought it might be cool to put a slight delay between each item that's added, so there would be a nice cascade sweeping across (LB uses a horizontal StackPanel) as all the items are added. Since I'll never have a result set > 10 items this doesn't seem too bad to me.
The problem is, the listbox does not add the item after each add, but waits until my method is complete, and then shows all the new items en masse. So, for the (exaggerated) example below, my page freezes up for 10 seconds, and then all ten items show up.
private void bookItemsLoaded(DownloadStringCompletedEventArgs e) {
BookResults.Clear();
foreach (AmazonTitleSearchResultDTO item in BookItemDTOLoader.LoadObjects(e.Result)) {
BookResults.Add(new AmazonExplorerBookItemViewModel() { ImageURL = item.CoverURL, Title = item.Title, ASIN = item.ASIN });
Thread.Sleep(1000);
}
}
How can I get Silverlight to show one item per second? (yes, I know that would be an excruciating user experience. The real delay will be much smaller)
[Here's the link to the article showing how to do the LB item animations, though most people reading this have probably seen it already]
EDIT
The answer below is perfect, but here's a slightly simpler version, sans recursion.
//get all the items to add i开发者_运维百科nto a local, tmeporary list, and call this method:
private void AddBookToResults(List<AmazonTitleSearchResultDTO> bookList)
{
DispatcherTimer Timer = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 1) };
int index = 0;
Timer.Tick += (s, e) => {
ItemCollection.Add(temp[index++]);
if (index == temp.Count)
Timer.Stop();
};
Timer.Start();
}
The problem is that your entire calculation is taking place on the main thread, and the actual UI animations don't take place until your method completes and gives the UI drawing code a chance to run again. This is why all of the animations happen "at once", even though you waited after adding each one. If you want to avoid this, you'll need to program your loop as a series of delegates to run on the main thread.
private void bookItemsLoaded(DownloadStringCompletedEventArgs e) {
BookResults.Clear();
var bookList = BookItemDTOLoader.LoadObjects(e.Result).ToList();
AddBookToResults(bookList, 0);
}
private void AddBookToResults(List<AmazonTitleSearchResultDTO> bookList, int index)
{
if (index == bookList.Count) {
return;
}
var item = bookList[index];
BookResults.Add(new AmazonExplorerBookItemViewModel() { ImageURL = item.CoverURL, Title = item.Title, ASIN = item.ASIN });
var timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 1);
timer.Tick += () => {
timer.Stop();
AddBookToResults(bookList, index + 1);
};
timer.Start();
}
An alternate solution is to have the loop run on a background thread. This is less reliable than the single-threaded delegate version, but it's also less code, and may be easier to understand.
精彩评论