Silverlight ObservableCollection with AddRange

7. October 2011 07:00 by Mrojas in   //  Tags: , , , , , , , , , , ,   //   Comments (0)

Silverlight is when you have to add a lot of items.
I know, I know maybe you should choose another way to show that data,
but leaving philosophical-ui design discussions, the real problem is that
usually those components are bind  to ObservableCollections.

ObservableCollections are a bit of an exhibitionist.
Each time you add an item it will yell

Hey!! Yoo-hoo! HEY!!! YOU!!
I'm HEREEEEEEEEEEEEEEEEEE!!!!
Look at me!! Look at Me!!! Look Mom No Hands!!! Look Dad no Feet!!! HEY!!!!!!!!

So if you have some code like:

for(int i=0;i<10000;i++)
{
    comboItems.Add("item" + i);
}


A nice thing will be to be able to do something like:

var items = new String[10000] 
for(int i=0;i<10000;i++) 
{ 
    items[i]="item" + i; 
} 
comboItems.AddRange(items); 


And then provide just ONE notification of Collection Changed instead of a lot of
little cries for attention.

Well that is the reason for this new version of ObservableCollection that I call
RangeObservableCollection:

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;

namespace Utils
{
    public class RangeObservableCollection<T> : ObservableCollection<T>
    {
        private bool _suppressNotification = false;

        public RangeObservableCollection() : base() { }

        public RangeObservableCollection(IEnumerable<T> collection) : base(collection) { }

        protected override void OnPropertyChanged(System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (!_suppressNotification) base.OnPropertyChanged(e);
        }

        protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (!_suppressNotification)
                base.OnCollectionChanged(e);
        }

        /// <summary>
        /// Adds a collection suppressing notification per item and just raising a notification
        /// for the whole collection
        /// </summary>
        /// <param name="list"></param>
        public void AddRange(IEnumerable<T> list)
        {
            if (list == null) throw new ArgumentNullException("list");
            _suppressNotification = true;
            foreach (T item in list)
            {
                Add(item);
            }
            _suppressNotification = false;
            OnCollectionChanged(new System.Collections.Specialized.NotifyCollectionChangedEventArgs(System.Collections.Specialized.NotifyCollectionChangedAction.Reset));
        }

    }
    
}

Restoring simple lookup capabilities to Silverlight ListBox

27. January 2011 04:09 by Mrojas in General  //  Tags: , , , , , , ,   //   Comments (0)

VB6 and WinForms ListBox has the built in capability to provide a simple data look up. But the Silverlight ListBox does not.
So if you have a list with items:

Apple 
Airplane 
Blueberry 
Bee 
Car 
Zoo 
Animal Planet

And your current item is Apple when you press A the next current item will be Airplane

Apple 
Airplane 
Blueberry 
Bee 
Car 
Zoo 
Animal Planet

And the next time you press A the next current item will be Animal Planet

Apple 
Airplane 
Blueberry 
Bee 
Car 
Zoo 
Animal Planet

And the next time you press A the next current item will be Apple again

Ok to do in Silverlight you need to add a event handler. You can create a user control and this event handler and replace your listbox for your custom listbox or just add this event handler for the listboxes that need it. The code you need is the following:

void listbox1_KeyDown(object sender, KeyEventArgs e)
{
    String selectedText = this.listbox1.SelectedItem.ToString();
    String keyAsString = e.Key.ToString();
    int maxItems = listbox1.Items.Count;
    if (!String.IsNullOrEmpty(selectedText) && 
        !String.IsNullOrEmpty(keyAsString) && keyAsString.Length == 1 && 
         maxItems > 1)
    {   
        
        int currentIndex = this.listbox1.SelectedIndex;
        int nextIndex    = (currentIndex + 1) % maxItems;
        while (currentIndex != nextIndex)
        {
            if (this.listbox1.Items[nextIndex].ToString().ToUpper().StartsWith(keyAsString))
            {
                this.listbox1.SelectedIndex = nextIndex;
                return;
            }   
            nextIndex    = (nextIndex + 1) % maxItems;   
        }
        //NOTE: theres is a slight different behaviour because for example in 
        //winforms if your only had an item that started with A and press A the selectionIndex
        //will not change but a SelectedIndexChanged event (equivalent to SelectionChanged in Silverlight)
        //and this is not the Silverlight behaviour
    }
    
}

Categories