ListView ItemsSource auto-update

Oct 14, 2010 at 8:04 PM

Hello,

What should i pass to a listview's itemssource to automaticly have it updating when the itemssource changes? I tried BindingList, but it gives me renderexceptions

Thanks,

Johnny

Oct 22, 2010 at 1:08 PM

Hello Johnny,

If your ItemsSource is IBindingList than your list will automatically be updated when it changes. Meaning when a data item is added, moved or removed or when the list is rebuilt.

Check how ListView.OnBindingListChanged() is implemented for details.

 

If you want to observe when some property of a data item changes, than you need a bit of extra work.

First your item data needs to expose property change notifications by implementing INotifyPropertyChanged or by providing a change for each property you want to observe or by other means.

And than you have to bind to the item data in order to receive change notifications. You may do it when the value is set to the list view control item.

 

See the attached sample:

 

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
//using System.Windows.Forms; // BindingSource
using Silvermoon.Controls;
using Silvermoon.Windows;


namespace zzRaul.Play {


	public class ListViewBindingTestPage : Page {

		class MyItemData {
			private static readonly Color[] TEXT_COLORS = {
				PhoneColors.Lime, PhoneColors.Orange, PhoneColors.Brown, PhoneColors.Green
			};

			private int _textColorIndex;


			public String Text { get; set; }


			public Color TextColor { 
				get { 
					return TEXT_COLORS[_textColorIndex]; 
				} 		
			}

			public event EventHandler TextColorChanged;

			public void ChangeTextColor() {
				_textColorIndex = (++_textColorIndex) % TEXT_COLORS.Length;
				if (TextColorChanged != null) {
					TextColorChanged(this, EventArgs.Empty);
				}
			}
		}

		class MyItem : TextItem {
			private MyItemData _myItemData;

			protected override void OnDataChanged() {
				//base.OnDataChanged();//empty

				Unbind();

				_myItemData = DataValue as MyItemData;
				if (_myItemData != null) {
					Text = _myItemData.Text;
					TextColor = _myItemData.TextColor;

					Bind();
				}
			}

			protected override void Dispose(bool dispose) {
				Unbind();
				base.Dispose(dispose);
			}

			private void Bind() {
				Debug.Assert(_myItemData != null);
				_myItemData.TextColorChanged += _myItemData_TextColorChanged;
			}

			void _myItemData_TextColorChanged(object sender, EventArgs evt) {
				Debug.Assert(sender == _myItemData);
				TextColor = ((MyItemData) sender).TextColor;
			}

			private void Unbind() {
				if (_myItemData != null) {
					_myItemData.TextColorChanged -= _myItemData_TextColorChanged;
				}
			}
		}


		#region Controls
		private ListView _listView;
		#endregion

		#region Model
		private static readonly int ITEM_COUNT = 5;
		private IBindingList _dataSource;
		#endregion


		#region Behavior
		private UITimer _timer;
		private int _tick;

		private static readonly int TICK_INTERVAL_MILLIS = 1 * 1000;
		private static readonly int TICKS_TO_CHANGE_COLOR = 1;
		private static readonly int TICKS_TO_REMOVE_ITEM = 3;
		#endregion


		public ListViewBindingTestPage() : base() {
			CreatePage();
		}
		private void CreatePage() {
			Title = "LIST VIEW BINDING TEST";

			CreateDataSource();

			_listView = new Silvermoon.Controls.ListView { Multiselect = false, Margin = Margin.Zero };
			_listView.GetVirtualItem += new EventHandler<ItemEventArgs>(_listView_GetVirtualItem);
			_listView.ItemsSource = _dataSource;

			Controls.Add(_listView);
		}

		void _listView_GetVirtualItem(object sender, ItemEventArgs evt) {
			evt.Item = new MyItem();
		}


		protected override void OnShown() {
			base.OnShown();

			StartTicking();
		}

		private void CreateDataSource() {
			Debug.Assert(_dataSource == null);
			_dataSource = new System.Windows.Forms.BindingSource();
			for (int i = 1; i <= ITEM_COUNT; i++) {
				_dataSource.Add(new MyItemData {
					Text = string.Format("Item {0}", i), 
				});
			}
		}

		private void StartTicking() {
			Debug.Assert(_timer == null);
			_timer = new UITimer { Interval = TICK_INTERVAL_MILLIS, Repeated = true };
			_timer.Tick += _timer_Tick;
			_timer.Start();
		}

		void _timer_Tick(object sender, EventArgs e) {
			OnTick();
		}

		private void OnTick() {
			_tick = (++_tick) % TICKS_TO_REMOVE_ITEM;
			if (_tick == 0 && _dataSource.Count > 0) {

				//_dataSource.RemoveAt(0);
				//_dataSource.RemoveAt(_dataSource.Count - 1);
				_dataSource.RemoveAt(Math.Min(_dataSource.Count % 2, _dataSource.Count - 1));

				if (_dataSource.Count == 0) {
					StopTicking();
					Screen.Close();
				}
			}
			if (_tick % TICKS_TO_CHANGE_COLOR == 0) {
				foreach (var itemData in _dataSource) {
					((MyItemData) itemData).ChangeTextColor();
				}
			}
		}

		private void StopTicking() {
			if (_timer != null) {
				_timer.Tick -= _timer_Tick;
				_timer.Dispose();
				_timer = null;
			}
		}

		protected override void Dispose(bool dispose) {
			StopTicking();

			base.Dispose(dispose);
		}



	}
}
Oct 28, 2010 at 9:32 AM

Thanks! Very helpfull!