namespace OpenNETCF.Windows.Forms
{
/// <summary>
/// Extended ComboBox control.
/// </summary>
public class ComboBoxEx : ComboBox, IWin32Window
{
//windows messages
private const int WM_SETREDRAW = 0x0b;
private const int CB_SETCURSEL = 0x014E;
private const int CB_DELETESTRING = 0x0144;
private const int CB_INSERTSTRING = 0x014A;
//native window handle
private IntPtr m_handle;
//databound collection
private IBindingList thebindinglist = null;
//is display updatable?
private bool m_updatable = true;
/// <summary>
/// Gets the window handle that the control is bound to.
/// </summary>
public IntPtr Handle
{
get
{
if(m_handle == IntPtr.Zero)
{
this.Capture = true;
m_handle = Win32Window.GetCapture();
this.Capture = false;
}
return m_handle;
}
}
// Redraw code courtesy of Alex Feinman – http://blog.opennetcf.org/afeinman/PermaLink,guid,9305a1d9-e24e-4310-89e2-f80808076a37.aspx
/// <summary>
/// Maintains performance when items are added to the <see cref=”ComboBoxEx”/> one at a time.
/// </summary>
public void BeginUpdate()
{
m_updatable = false;
Win32Window.SendMessage(this.Handle, WM_SETREDRAW, 0, 0);
}
/// <summary>
/// Resumes painting the <see cref=”ComboBoxEx”/> control after painting is suspended by the <see cref=”BeginUpdate”/> method.
/// </summary>
public void EndUpdate()
{
m_updatable = true;
Win32Window.SendMessage(this.Handle, WM_SETREDRAW, 1, 0);
}
//ComboBox doesn’t support ItemChanges in a datasource implementing IBindingList
//The following workaround forces the list to update if an item is changed
//data source has changed
protected override void OnDataSourceChanged(EventArgs e)
{
//remove event handler
if(thebindinglist != null)
{
thebindinglist.ListChanged-= new ListChangedEventHandler(ComboBoxEx_ListChanged);
//reset our handle to the bound data
thebindinglist = null;
}
//get the underlying ibindinglist (if there is one)
if(this.DataSource is IListSource)
{
IList thelist = ((IListSource)this.DataSource).GetList();
if(thelist is IBindingList)
{
thebindinglist = (IBindingList)thelist;
}
}
else if(this.DataSource is IBindingList)
{
thebindinglist = (IBindingList)this.DataSource;
}
if(thebindinglist != null)
{
//hook up event for data changed
thebindinglist.ListChanged+=new ListChangedEventHandler(ComboBoxEx_ListChanged);
}
base.OnDataSourceChanged (e);
}
//called when a change occurs in the bound collection
private void ComboBoxEx_ListChanged(object sender, ListChangedEventArgs e)
{
if(m_updatable)
{
if (e.ListChangedType == ListChangedType.ItemChanged)
{
//update the item
//delete old item
Win32Window.SendMessage(this.Handle, CB_DELETESTRING, e.NewIndex, 0);
//get display text for new item
string newval = this.GetItemText(this.Items[e.NewIndex]);
//marshal to native memory
IntPtr pString = MarshalEx.StringToHGlobalUni(newval);
//send message to native control
Win32Window.SendMessage(this.Handle, CB_INSERTSTRING, e.NewIndex, pString);
//free native memory
MarshalEx.FreeHGlobal(pString);
}
}
}
/// <summary>
/// Get or Set the selected index in collection.
/// </summary>
/// <remarks>Overridden to overcome issue with setting value to -1 (http://support.microsoft.com/default.aspx?scid=kb;en-us;327244)</remarks>
public override int SelectedIndex
{
get
{
return base.SelectedIndex;
}
set
{
if(value == -1)
{
Win32Window.SendMessage(this.Handle, CB_SETCURSEL, -1, 0);
}
else
{
base.SelectedIndex = value;
}
}
}
}
}