context: using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Reflection;
  using System.Runtime.InteropServices;
  using System.Windows.Forms;
  
  namespace FalloutSnip.Windows.Controls
  {
      /// <summary>
      /// Summary description for BindingListView.
      /// </summary>
      public class BindingListView : VirtualListView
      {
          private IList _data;
  
          private int lvcacheStart = -1;
          private int lvcacheEnd = -1;
          private readonly List<ListViewItem> lvcache = new List<ListViewItem>();
  
          public BindingListView()
          {
              InitializeComponent();
  
              FullRowSelect = true;
              HideSelection = false;
              View = View.Details;
              base.QueryItemText += BindingListView_QueryItemText;
              base.CacheVirtualItems += BindingListView_CacheVirtualItems;
              base.RetrieveVirtualItem += BindingListView_RetrieveVirtualItem;
          }
  
          [DllImport("uxtheme.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
          internal static extern int SetWindowTheme(IntPtr hWnd, string appName, string partList);
  
          // You can subclass ListView and override this method
          protected override void OnHandleCreated(EventArgs e)
          {
              base.OnHandleCreated(e);
              SetWindowTheme(Handle, "explorer", null);
          }
  
          private ListViewItem CreateBlankListViewItem()
          {
              var subItems = new ListViewItem.ListViewSubItem[Columns.Count];
              for (int i = 0; i < subItems.Length; ++i)
                  subItems[i] = new ListViewItem.ListViewSubItem();
              return new ListViewItem(subItems, -1);
          }
  
          private void FillListViewItem(ListViewItem lvItem, int index)
          {
              if (index >= 0 && _data != null && index < _data.Count)
              {
                  object item = _data[index];
                  for (int i = 0; i < lvItem.SubItems.Count; ++i)
                  {
                      var header = Columns[i] as ColumnBinding;
                      var subItem = lvItem.SubItems[i];
                      if (header != null)
                      {
                          object value = header.GetPropertyValue(item);
                          if (value != null) subItem.Text = value.ToString();
                      }
                  }
              }
          }
  
          private void BindingListView_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
          {
              if (e.ItemIndex >= lvcacheStart && e.ItemIndex <= lvcacheEnd)
              {
                  e.Item = lvcache[e.ItemIndex - lvcacheStart];
              }
              else
              {
                  e.Item = CreateBlankListViewItem();
                  FillListViewItem(e.Item, e.ItemIndex);
              }
          }
  
          private void BindingListView_CacheVirtualItems(object sender, CacheVirtualItemsEventArgs e)
          {
              int len = e.EndIndex - e.StartIndex + 1;
              lvcacheStart = e.StartIndex;
              if (len != lvcache.Count)
              {
                  if (lvcache.Capacity < len)
                      lvcache.Capacity = len;
                  while (lvcache.Count < len)
                      lvcache.Add(CreateBlankListViewItem());
                  if (lvcache.Count > len)
                      lvcache.RemoveRange(len, lvcache.Count - len);
              }
              for (int i = 0; i < lvcache.Count; ++i)
              {
                  FillListViewItem(lvcache[i], e.StartIndex + i);
              }
          }
  
          private event QueryItemTextHandler _QueryItemText;
  
          public new event QueryItemTextHandler QueryItemText
          {
              add { _QueryItemText += value; }
              remove { _QueryItemText -= value; }
          }
  
  
          public new IList Items
          {
              get { return _data; }
          }
  
  
          public ColumnBinding AddBindingColumn<T, TResult>(string PropertyName, string DisplayName)
          {
              var column = new ColumnBinding();
              column.Text = DisplayName;
              column.Property = new ColumnPropertyDescriptor<T, TResult>(PropertyName, null);
              Columns.Add(column);
              return column;
          }
  
          public ColumnBinding AddBindingColumn<T, TResult>(string PropertyName, string DisplayName, int width)
          {
              ColumnBinding column = AddBindingColumn<T, TResult>(PropertyName, DisplayName);
              column.Width = width;
              return column;
          }
  
          public ColumnBinding AddBindingColumn<T, TResult>(string PropertyName, string DisplayName, int width,
                                                            Delegate transform)
          {
              ColumnBinding column = AddBindingColumn<T, TResult>(PropertyName, DisplayName, width);
              column.Property = new ColumnPropertyDescriptor<T, TResult>(PropertyName, transform);
              return column;
          }
  
          public ColumnBinding AddBindingColumn<T, TResult>(string PropertyName, string DisplayName, int width,
                                                            HorizontalAlignment textAlign)
          {
              ColumnBinding column = AddBindingColumn<T, TResult>(PropertyName, DisplayName, width);
              column.TextAlign = textAlign;
              return column;
          }
  
          public ColumnBinding AddBindingColumn<T, TResult>(string PropertyName, string DisplayName, int width,
                                                            HorizontalAlignment textAlign, Delegate transform)
          {
              ColumnBinding column = AddBindingColumn<T, TResult>(PropertyName, DisplayName, width, textAlign);
              column.Property = new ColumnPropertyDescriptor<T, TResult>(PropertyName, transform);
              return column;
          }
  
          public ColumnBinding AddBindingColumn(string PropertyName, string DisplayName)
          {
              var column = new ColumnBinding();
              column.Text = DisplayName;
              column.Property = new ColumnPropertyDescriptor<object, string>(PropertyName, null);
              Columns.Add(column);
              return column;
          }
  
          public ColumnBinding AddBindingColumn(string PropertyName, string DisplayName, int width)
          {
              ColumnBinding column = AddBindingColumn(PropertyName, DisplayName);
              column.Width = width;
              return column;
          }
  
          public ColumnBinding AddBindingColumn(string PropertyName, string DisplayName, int width, Delegate transform)
          {
              ColumnBinding column = AddBindingColumn(PropertyName, DisplayName, width);
              column.Property = new ColumnPropertyDescriptor<object, string>(PropertyName, transform);
              return column;
          }
  
          public ColumnBinding AddBindingColumn(string PropertyName, string DisplayName, int width,
                                                HorizontalAlignment textAlign)
          {
              ColumnBinding column = AddBindingColumn(PropertyName, DisplayName, width);
              column.TextAlign = textAlign;
              return column;
          }
  
          public ColumnBinding AddBindingColumn(string PropertyName, string DisplayName, int width,
                                                HorizontalAlignment textAlign, Delegate transform)
          {
              ColumnBinding column = AddBindingColumn(PropertyName, DisplayName, width, textAlign);
              column.Property = new ColumnPropertyDescriptor<object, string>(PropertyName, transform);
              return column;
          }
  
          public void AddBindingColumn(PropertyDescriptor property)
          {
              var column = new ColumnBinding();
              column.Text = property.DisplayName;
              column.Property = property;
              Columns.Add(column);
          }
  
          public void AddBindingColumn(PropertyDescriptor property, string DisplayName)
          {
              var column = new ColumnBinding();
              column.Text = DisplayName;
              column.Property = property;
              Columns.Add(column);
          }
  
          public void AddBindingColumn(PropertyDescriptor property, string DisplayName, int width)
          {
              var column = new ColumnBinding();
              column.Text = DisplayName;
              column.Property = property;
              column.Width = width;
              Columns.Add(column);
          }
  
          public void AddBindingColumn(PropertyDescriptor property, string DisplayName, int width,
                                       HorizontalAlignment textAlign)
          {
              var column = new ColumnBinding();
              column.Text = DisplayName;
              column.Property = property;
              column.Width = width;
              column.TextAlign = textAlign;
              Columns.Add(column);
          }
  
          public void RemoveBindingColumns(string PropertyName)
          {
              foreach (ColumnBinding column in Columns)
              {
                  if ((column.Property != null && column.Property.Name == PropertyName)
                      || (column.FieldName == PropertyName)
                      )
                  {
                      Columns.Remove(column);
                      break;
                  }
              }
          }
  
          public ColumnBinding GetColumnBinding(int column)
          {
              return (column >= 0 && column < Columns.Count) ? Columns[column] as ColumnBinding : null;
          }
  
          public void ClearBindingColumns()
          {
              Columns.Clear();
          }
  
          public IList DataSource
          {
              get { return _data; }
              set
              {
                  if (_data != value)
                  {
                      var list = _data as IBindingList;
                      if (list != null) list.ListChanged -= DataSource_ListChanged;
  
                      _data = value;
  
                      list = _data as IBindingList;
                      if (list != null) list.ListChanged += DataSource_ListChanged;
  
                      if (Columns.Count == 0 && _data is ITypedList)
                      {
                          var typedList = _data as ITypedList;
                          PropertyDescriptorCollection properties = typedList.GetItemProperties(null);
  
gt:                         if (properties != null)