It's been a long long time I have been posting. It's not that time stood still, but I wondered what I or why I should write.
At the moment web 2.0 is hot. We are trying to understand a new platform called cloud computing. Software is becoming more a service (SaaS). With all these inventions, we have to step on this train. So it's time to I know what they really talk about.
Is there someone who know's what web 2.0 is? Read it at wikipedia. So is it clear for you now? Not yet is it? Is is just a summation of what has been achieved the last year at internet? Yes that is it: RIA's, Social network sites, Interactive websites and services. A lot of new technologies combined fall under web 2.0: AJAX, Silverlight, Web services. A lot of public sites or services that are widely and common used: Google Search, Google maps, Google Docs, youtube, LinkedIn, Hyves.
Unfortunately the new IPV6 protocol is not part of Web 2.0.
Is there someone who know's what is cloud computing? This video gives a clear explanation of it.
It's certainly more than hiring capacity at a hosting party. Microsoft is developing Windows Azure (cloud computing). read more.... It's a kind of platform where you can deploy your services. May be you think that Microsoft invented it. But that's not true. Amazon has already a similar platform live. read more.... Also Google and IBM cooperate and deliver cloud computing services. read more...
A good example of a cloud computing product is outlook cloud
More on cloud computing (cloud applications)
ZDNet video
Cloud applications
Thursday, January 22, 2009
Friday, March 02, 2007
Reflection overload
More often I am using Reflection. I translate DataSource objects to collections, DataTable object etc. The underlying reason is that I used datasource objects in controls. And most controls have a display and a ValueMember. The ComboBox Column in a DataGridView controls seems to be very slow. I think it Microsoft uses the IList interface for all DataSource objects. In case of a ComboBoxColumn an dictionary object would be more approriate. A dictionary object works with a hash key, a kind of database index. Only it has not a Ilist interface. The dictionary gives a performance boost. But how do I translate a IList DataSource to a non IList DataSource and use it?
See here a possible solution
The dictionary is of template types: string, string. You could easily change this in Dictionary
See here a possible solution
public static Dictionary DataSourceToDictionary(object dataSource, string valueMember, string displayMember)
{
IList list = dataSource as IList;
Dictionary listLookup = new Dictionary();
if (list != null && list.Count > 0)
{
PropertyInfo valueMemberInfo = dataSource.GetType().GetGenericArguments()[0].GetProperty(valueMember);
PropertyInfo displayMemberInfo = dataSource.GetType().GetGenericArguments()[0].GetProperty(displayMember);
foreach (object item in list)
{
listLookup.Add(valueMemberInfo.GetValue(item, null).ToString(), displayMemberInfo.GetValue(item, null).ToString());
}
}
return listLookup;
}
The dictionary is of template types: string, string. You could easily change this in Dictionary
Thursday, February 01, 2007
Yet another Nullable DateTimePicker
I was looking for a nullable datetime picker that supported the DateTime? type. I found a good one at Claudio's blog, at 25 April. This is just what I was looking for.
I added another feature to set the BackColor of the picker. The background have to be set in the WndProc as well (hmm).
If you are interested, this is the full source. I have made some other changes as well. The delete key will erase the date value. I added that, if you type a key on a null date, the today value will be set. This makes it possible to edit the value of the textbox again.
I added another feature to set the BackColor of the picker. The background have to be set in the WndProc as well (hmm).
protected override void WndProc(ref Message m)
{
// Check to see if message being send is WM_ERASEBKGND.
// The hex value of this message is hex 14.
// This message is sent when the background of the
// object needs to be erased. In our case though, instead of
// erasing it, we will paint a rectangle over it
if (m.Msg == 0x14 && Enabled) // Then ' WM_ERASEBKGND
{
using (Graphics g = Graphics.FromHdc(m.WParam))
{
g.FillRectangle(new SolidBrush(BackColor), ClientRectangle);
}
return;
}
if (m.Msg == 0x4e) // WM_NOTIFY
{
NMHDR nm = (NMHDR) m.GetLParam(typeof (NMHDR));
if (nm.Code == -746 nm.Code == -722) // DTN_CLOSEUP DTN_?
if (isNull)
{
SetToDateTimeValue();
}
}
base.WndProc(ref m);
}
If you are interested, this is the full source. I have made some other changes as well. The delete key will erase the date value. I added that, if you type a key on a null date, the today value will be set. This makes it possible to edit the value of the textbox again.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace XXX.WinControls
{
public class DatePicker : DateTimePicker
{
#region member variables
[StructLayout(LayoutKind.Sequential)]
private struct NMHDR
{
public IntPtr HwndFrom;
public int IdFrom;
public int Code;
}
// true, when no date shall be displayed (empty DateTimePicker)
private bool isNull;
// If _isNull = true, this value is shown in the DTP
private string nullValueText = "(none)";
private string customFormat;
private DateTimePickerFormat format;
private string formatAsString;
#endregion
[Browsable(true),DesignerSerializationVisibility(DesignerSerializationVisibility.Visible) ]
[Category("Appearance"),Description("Gets or sets the BackColor") ]
public override Color BackColor
{
get
{
return base.BackColor;
}
set
{
base.BackColor = value;
}
}
[Category("Appearance"), Description("Sets or gets the Null value text"),DefaultValue("(None)") ]
public String NullValueText
{
get { return nullValueText; }
set { nullValueText = value; }
}
public new String CustomFormat
{
get { return customFormat; }
set
{
customFormat = value;
SetFormat();
}
}
public new DateTimePickerFormat Format
{
get { return format; }
set
{
format = value;
SetFormat();
Invalidate();
OnFormatChanged(EventArgs.Empty);
}
}
[Category("Data"),Browsable(true), Description("Sets or gets the value "),Bindable(true)]
public new DateTime? Value
{
get
{
if (isNull)
{
return null;
}
else
{
return base.Value;
}
}
set
{
if (value.HasValue)
{
base.Value = value.Value;
SetToDateTimeValue();
}
else
{
isNull = true;
SetToNullValue();
Invalidate();
}
}
}
private string FormatAsString
{
get { return formatAsString; }
set
{
formatAsString = value;
base.CustomFormat = value;
}
}
protected override void WndProc(ref Message m)
{
// Check to see if message being send is WM_ERASEBKGND.
// The hex value of this message is hex 14.
// This message is sent when the background of the
// object needs to be erased. In our case though, instead of
// erasing it, we will paint a rectangle over it
if (m.Msg == 0x14 && Enabled) // Then ' WM_ERASEBKGND
{
using (Graphics g = Graphics.FromHdc(m.WParam))
{
g.FillRectangle(new SolidBrush(BackColor), ClientRectangle);
}
return;
}
if (m.Msg == 0x4e) // WM_NOTIFY
{
NMHDR nm = (NMHDR) m.GetLParam(typeof (NMHDR));
if (nm.Code == -746 nm.Code == -722) // DTN_CLOSEUP DTN_?
if (isNull)
{
SetToDateTimeValue();
}
}
base.WndProc(ref m);
}
public DatePicker()
{
base.Format = DateTimePickerFormat.Custom;
this.Format = DateTimePickerFormat.Short;
Value = null;
}
private void SetFormat()
{
CultureInfo ci = Thread.CurrentThread.CurrentUICulture;
DateTimeFormatInfo dtf = ci.DateTimeFormat;
switch (format)
{
case DateTimePickerFormat.Long:
FormatAsString = dtf.LongDatePattern;
break;
case DateTimePickerFormat.Short:
FormatAsString = dtf.ShortDatePattern;
break;
case DateTimePickerFormat.Time:
FormatAsString = dtf.ShortTimePattern;
break;
case DateTimePickerFormat.Custom:
FormatAsString = this.CustomFormat;
break;
}
}
private void SetToDateTimeValue()
{
if (isNull)
{
SetFormat();
isNull = false;
//base.OnValueChanged(new EventArgs());
}
}
private void SetToNullValue()
{
isNull = true;
base.CustomFormat = String.IsNullOrEmpty(nullValueText) ? " " : "'" + NullValueText + "'";
}
/*
protected override void OnCloseUp(EventArgs e)
{
if (Control.MouseButtons == MouseButtons.None && isNull)
{
SetToDateTimeValue();
}
base.OnCloseUp(e);
}*/
protected override void OnKeyUp(KeyEventArgs e)
{
if (isNull)
{
Value = DateTime.Today;
SetToDateTimeValue();
}
if (!isNull && e.KeyCode == Keys.Delete)
{
this.Value = null;
OnValueChanged(EventArgs.Empty);
}
base.OnKeyUp(e);
}
}
}
Reflection on Generic Lists for getting the item type
I needed to find out what kind of Generic list, I had created. But I did'nt find a reflection property to get the type.
The type name of the generic list is [Namespace] '1 [[ [Item Type your looking for ']]
e.g.
List list = new list();
Type listType = list.GetType();
string listFullTypeName = listType.FullName;
int idxStart = listFullTypeName.IndexOf("'1[[")+4;
int idxEnd =listFullTypeName.IndexOf("]]");
string itemTypeName = listFullTypeName.Substring(idxStart,idxEnd-idxStart);
To get the real item type, I have to get the type from the itemTypeName string
Type type = Type.GetType(itemTypeName);
That's all
The type name of the generic list is [Namespace] '1 [[ [Item Type your looking for ']]
e.g.
List
Type listType = list.GetType();
string listFullTypeName = listType.FullName;
int idxStart = listFullTypeName.IndexOf("'1[[")+4;
int idxEnd =listFullTypeName.IndexOf("]]");
string itemTypeName = listFullTypeName.Substring(idxStart,idxEnd-idxStart);
To get the real item type, I have to get the type from the itemTypeName string
Type type = Type.GetType(itemTypeName);
That's all
Wednesday, January 10, 2007
Create a Custom configuration section in the App.Config with C#
Introduction
A custom section in the application configuration is defined as a Configuration Section. Derive a new class from the Configuration Section class and add some properties to it. The class should also be marked as serializable. The properties read and write string values from and to the application configuration file. For other value-types, cast the properties to the right type. Add for each property a Configuration Attribute or Element. The Configuration property will default thread the property as an attribute in the CacheConfigurationSection.
Validation attributes
Because all values are of a given string type, additional validation have to b e made. Some attributes can be added to the properties to restrict the configuration values.
Checking a string
[StringValidator(InvalidCharacters = " ~!@#$%^&*()[]{}/;'\"\\", MinLength = 1, MaxLength = 60)]
Checking a long
[LongValidator(MinValue = 1, MaxValue = 1000000, ExcludeRange = false)]
Configuration XMLElementS instead of attributres
Properties can be persisted as element. The property must be derived class from the baseclass configuration Element.
The child property is defined as any other property
Changes to the application config file
In the Application Configuration the section has to be declared
Also the data of the Custom Configuration should be added
The publicKeyToken is the key that belongs to the strong name. If no strong name is used, the PublicKeyToken is null. With the Strong Name utilty the public key of the DLL can be retrieved. Usage: SN -T MyCustomSection.DLL.
Using the custom CacheConfigurationSection
Get the section data with use of the Configuration Manager and cast the value to the Custom ConfigurationSection class.
CacheConfigurationSection config =
(CacheConfigurationSection) ConfigurationManager.GetSection("CacheConfigurationSection");
//Now we can use it
if (!config.Enabled)
{
return;
}
Source MSDN
Configuration Section
Custom configuration Section
A custom section in the application configuration is defined as a Configuration Section. Derive a new class from the Configuration Section class and add some properties to it. The class should also be marked as serializable. The properties read and write string values from and to the application configuration file. For other value-types, cast the properties to the right type. Add for each property a Configuration Attribute or Element. The Configuration property will default thread the property as an attribute in the CacheConfigurationSection.
[Serializable]
public class CacheConfigurationSection : ConfigurationSection
[ConfigurationProperty("CacheExpirationTimeout", DefaultValue =
"01:00:00",
IsRequired = true)]
public String CacheExpirationTimeout
{
get
{ return (String)this["CacheExpirationTimeout"]; }
set
{ this["CacheExpirationTimeout"] = value; }
}
[ConfigurationProperty("Enabled", DefaultValue =
"true",
IsRequired = true)]
public bool Enabled
{
get
{ return Convert.ToBoolean(this["Enabled"]); }
set
{ this["Enabled"] = value; }
}
Validation attributes
Because all values are of a given string type, additional validation have to b e made. Some attributes can be added to the properties to restrict the configuration values.
Checking a string
[StringValidator(InvalidCharacters = " ~!@#$%^&*()[]{}/;'\"\\", MinLength = 1, MaxLength = 60)]
Checking a long
[LongValidator(MinValue = 1, MaxValue = 1000000, ExcludeRange = false)]
Configuration XMLElementS instead of attributres
Properties can be persisted as element. The property must be derived class from the baseclass configuration Element.
public class MyChildConfigElement : ConfigurationElement
The child property is defined as any other property
[ConfigurationProperty("myChildSection")]
public MyChildConfigElement MyChildSection
{
…
}
Changes to the application config file
In the Application Configuration the section has to be declared
Also the data of the Custom Configuration should be added
configuration>
configSections>
section name="CacheConfigurationSection" type="Company.Framework.Data.DTO.CacheConfigurationSection, Company.Framework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=564525624cd0845a" /
/configSections
CacheConfigurationSection DTOCacheFileName="ReferenceCache.xml" CacheExpirationTimeout="01:00:00" Enabled="true" /
/configuration
The publicKeyToken is the key that belongs to the strong name. If no strong name is used, the PublicKeyToken is null. With the Strong Name utilty the public key of the DLL can be retrieved. Usage: SN -T MyCustomSection.DLL.
Using the custom CacheConfigurationSection
Get the section data with use of the Configuration Manager and cast the value to the Custom ConfigurationSection class.
CacheConfigurationSection config =
(CacheConfigurationSection) ConfigurationManager.GetSection("CacheConfigurationSection");
//Now we can use it
if (!config.Enabled)
{
return;
}
Source MSDN
Configuration Section
Custom configuration Section
Thursday, December 28, 2006
CheckBoxCombo continued
The complete listening is here:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Collections;
namespace PlannerControl
{
public class CheckBoxCombo : CustomComboBox
{
///
/// Occurs if the list changed
///
private ListChangedEventHandler listChangedHandler;
///
/// Occurs if the position changed
///
private EventHandler positionChangedHandler;
///
/// Occurs if the data source changes
///
public EventHandler DataSourceChanged;
///
/// Occurs if the value member changes
///
public EventHandler DisplayMemberChanged;
private string displayMember;
private PropertyInfo propInfoItemDisplayMember;
private Dictionary objectCollection;
private CheckedListBox checkedListBox;
private object dataSource;
private string itemsDisplayMember;
private ControlPopup popup;
private PropertyInfo propInfoItemsDisplayMember;
private int listWidth;
private string allText="ALL";
private string checkAllText="Check All";
private string uncheckAllText="Uncheck All";
private bool autoContextMenu;
private CurrencyManager dataManager;
///
/// Get Checked Items
///
///
[Browsable(false) ]
public IEnumerator CheckedItemsEnumerator
{
get
{
return checkedListBox.CheckedItems.GetEnumerator();
}
}
///
/// True, if at least one item has been checked, otherwise returns false
///
[Browsable(false)]
public bool HasSelectedItems
{
get { return checkedListBox.CheckedItems.Count > 0; }
}
[Category("Appearance"),Description("Text for the default ContextMenu to check all items")]
public string CheckAllText
{
get { return checkAllText; }
set { checkAllText = value; }
}
[Category("Appearance"), Description("Text for the default ContextMenu to uncheck all items")]
public string UncheckAllText
{
get { return uncheckAllText; }
set { uncheckAllText = value; }
}
[Category("Appearance"), Description("Text that is displayed, if all items are checked.")]
public string AllText
{
get { return allText; }
set
{
allText = value;
Invalidate();
}
}
[Category("Appearance"), Description("If true sets an default ContextMenu to check and uncheck all items.")]
public bool AutoContextMenu
{
get { return autoContextMenu; }
set
{
autoContextMenu = value;
SetContextMenu(value);
}
}
///
/// Gets or Sets the backcolor of the dropdown list (including the combobox)
///
[Category("Appearance"), Description("Gets or sets the backcolor of the dropdown list."), BrowsableAttribute(true)]
public Color ListBackColor
{
get
{
return this.checkedListBox.BackColor;
}
set
{
this.checkedListBox.BackColor = value;
}
}
///
/// List width
///
[Category("Appearance"),Description("Gets or sets the list with of the checkedlistbox")]
public int ListWidth
{
get { return listWidth; }
set {
listWidth = value;
if (popup!=null)
{
listWidth = value;
}
}
}
///
/// Sets or Gets the ContextMenu of the CheckedListBox
///
[Category("Appearance"),Description("Gets or Sets the ContextMenu of the CheckedListBox")]
public ContextMenu ContextMenuListBox
{
get { return checkedListBox.ContextMenu ; }
set {checkedListBox.ContextMenu = value; }
}
///
/// Sets or Gets the ContextMenuStrip of the CheckedListBox
///
[Category("Appearance"), Description("Gets or sets the ContextMenuStrip of the CheckedListBox")]
public ContextMenuStrip ContextMenuStripListBox
{
get { return checkedListBox.ContextMenuStrip; }
set { checkedListBox.ContextMenuStrip = value; }
}
///
/// DataSource
///
[Bindable(true)]
[TypeConverter("System.Windows.Forms.Design.DataSourceConverter, System.Design")]
[Category("Data")]
[DefaultValue(null)]
public object DataSource
{
get
{
return dataSource;
}
set
{
dataSource = value;
DataBind();
OnDataSourceChanged(EventArgs.Empty);
}
}
///
/// The record selected
///
[Browsable(false)]
protected CurrencyManager DataManager
{
get
{
return this.dataManager;
}
}
///
/// Sets or Gets the DisplayMember of the DataSource
///
[Category("Data"),Description("Gets or sets the DisplayMember of the DataSource")]
[Editor("System.Windows.Forms.Design.DataMemberListEditor, System.Design",
"System.Drawing.Design.UITypeEditor, System.Drawing")]
[DefaultValue(null)]
public string DisplayMember
{
get { return displayMember; }
set
{
displayMember = value;
OnDisplayMemberChanged(EventArgs.Empty);
}
}
///
/// Sets or Gets the ItemsDisplayMember
/// All Selected Items will be displayed with this item member in the TextBox Text
///
[Category("Data"),Description("Sets or gets the DisplayMember of the items in the ComboBox")]
public string ItemsDisplayMember
{
get { return itemsDisplayMember; }
set { itemsDisplayMember = value; propInfoItemsDisplayMember = null; }
}
/*
///
/// Returns the checklistbox items
///
[Category("Data"), Description("Gets the CheckedListBox items")]
public CheckedListBox.ObjectCollection Items
{
get
{
return checkedListBox.Items;
}
}
*/
///
/// Constructor
///
public CheckBoxCombo()
{
InitializeComponent();
objectCollection = new Dictionary();
checkedListBox = new CheckedListBox();
listWidth = Width;
checkedListBox.CheckOnClick = true;
checkedListBox.Location = new Point(0, 0);
checkedListBox.ScrollAlwaysVisible = true;
listChangedHandler = new ListChangedEventHandler(dataManager_ListChanged);
positionChangedHandler = new EventHandler(dataManager_PositionChanged);
}
///
/// Returns true if a checked item is found
///
///
///
public bool ContainsCheckedItem(object item)
{
//Loop the collection of selected indices
for (int i = 0; i < checkedListBox.SelectedIndices.Count; i++)
{
//Get the corresponding item
if (objectCollection[checkedListBox.SelectedIndices[i]]==item)
{
return true;
}
}
return false;
}
///
/// Search the checked list for a given value
///
///
///
///
public bool ContainsCheckedValue(string property, object value)
{
ArrayList list = GetSelectedItems();
bool found = false;
if (list.Count > 0)
{
PropertyInfo pi = list[0].GetType().GetProperty(property);
foreach (object item in list)
{
if (pi.GetValue(item, null) == value)
{
found = true;
}
}
}
return found;
}
private void DataBind()
{
propInfoItemDisplayMember = null;
propInfoItemsDisplayMember = null;
if (DataSource == null ||
base.BindingContext == null)
return;
CurrencyManager cm;
try
{
cm = base.BindingContext[this.DataSource] as CurrencyManager;
}
catch (ArgumentException)
{
// If no CurrencyManager was found
return;
}
//Other currency manager
if (this.dataManager != cm)
{
// Unwire the old CurrencyManager
if (this.dataManager != null)
{
this.dataManager.ListChanged -=
listChangedHandler;
this.dataManager.PositionChanged -=
positionChangedHandler;
}
checkedListBox.Items.Clear();
this.dataManager = cm;
// Wire the new CurrencyManager
if (this.dataManager != null)
{
this.dataManager.ListChanged +=
listChangedHandler;
this.dataManager.PositionChanged +=
positionChangedHandler;
}
// Update metadata and data
UpdateAllData();
}
}
private void dataManager_PositionChanged(object sender, EventArgs e)
{
if (checkedListBox.Items.Count > DataManager.Position)
{
checkedListBox.SelectedIndex =DataManager.Position;
}
}
private void dataManager_ListChanged(object sender, ListChangedEventArgs e)
{
if (e.ListChangedType == ListChangedType.Reset ||
e.ListChangedType == ListChangedType.ItemMoved)
{
// Update all data
UpdateAllData();
}
else if (e.ListChangedType == ListChangedType.ItemAdded)
{
// Add new Item
objectCollection.Add(e.NewIndex, dataManager.List[e.NewIndex]);
AddListItem(dataManager.List[e.NewIndex]);
}
else if (e.ListChangedType == ListChangedType.ItemChanged)
{
// Change Item
UpdateItem(e.NewIndex);
}
else if (e.ListChangedType == ListChangedType.ItemDeleted)
{
// Delete Item
DeleteItem(e.NewIndex);
}
else
{
// Update metadata and all data
UpdateAllData();
}
}
///
/// Removes an item
///
///
private void DeleteItem(int i)
{
checkedListBox.Items.RemoveAt(i);
if (objectCollection.ContainsKey(i))
{
objectCollection.Remove(i);
}
}
private void UpdateAllData()
{
checkedListBox.Items.Clear();
objectCollection.Clear();
for (int i = 0; i < DataManager.Count; i++)
{
objectCollection.Add(i, dataManager.List[i]);
AddListItem(dataManager.List[i]);
}
}
private void UpdateItem(int i)
{
object item = objectCollection[i];
checkedListBox.Items[i] = GetItemDisplayText(item);
}
private void AddListItem(object o)
{
string displayText = GetItemDisplayText(o);
checkedListBox.Items.Add(displayText);
}
private string GetItemDisplayText(object o)
{
string displayText = String.Empty;
if (!String.IsNullOrEmpty(this.displayMember))
{
if (propInfoItemDisplayMember == null)
{
propInfoItemDisplayMember = o.GetType().GetProperty(this.displayMember);
}
object value = propInfoItemDisplayMember.GetValue(o,null);
if (value != null)
{
displayText = value.ToString();
}
}
else if (o != null)
{
displayText = o.ToString();
}
return displayText;
}
///
/// Retrieves the selected items from the list.
///
///
/// The return value is an ArrayList
///
public ArrayList GetSelectedItems()
{
ArrayList listToReturn = new ArrayList();
if (checkedListBox.CheckedItems.Count > 0)
{
foreach (int index in checkedListBox.CheckedIndices)
{
listToReturn.Add(objectCollection[checkedListBox.CheckedIndices[index]]);
}
}
return listToReturn;
}
///
/// Return a list of values of the selected items
///
/// Value member of an list object
/// ArrayList
public ArrayList GetSelectedItems(string valueMember)
{
ArrayList listToReturn = new ArrayList();
if (checkedListBox.CheckedItems.Count > 0)
{
PropertyInfo pi = objectCollection[0].GetType().GetProperty(valueMember);
foreach (int index in checkedListBox.CheckedIndices)
{
object value = pi.GetValue(objectCollection[checkedListBox.CheckedIndices[index]], null);
listToReturn.Add(value);
}
}
return listToReturn;
}
///
/// Checks all items
///
public void CheckAll()
{
for(int i=0;i {
checkedListBox.SetItemChecked(i, true);
}
}
///
/// Returns the text for the ComboBox
///
///
private string GetComboBoxText()
{
//No items (checked)
if (checkedListBox.Items == null || checkedListBox.Items.Count == 0 || checkedListBox.CheckedIndices.Count == 0)
{
return "[]";
}
if (checkedListBox.CheckedIndices.Count==checkedListBox.Items.Count)
{
return String.Format("[{0}]", allText);
}
//Get the member to be displayed
if (!String.IsNullOrEmpty(itemsDisplayMember) && propInfoItemsDisplayMember == null)
{
propInfoItemsDisplayMember = objectCollection[0].GetType().GetProperty(itemsDisplayMember);
}
StringBuilder displayText = new StringBuilder("[");
if (propInfoItemsDisplayMember ==null)
{
for(int itemIndex =0;itemIndex {
object item = objectCollection[checkedListBox.CheckedIndices[itemIndex]];
displayText.Append(item.ToString());
displayText.Append(", ");
}
}
else
{
for(int itemIndex =0;itemIndex {
object value = propInfoItemsDisplayMember.GetValue(objectCollection[checkedListBox.CheckedIndices[itemIndex]] , null);
if (value==null)
{
value = String.Empty;
}
displayText.Append(value.ToString());
displayText.Append(", ");
}
}
displayText.Remove(displayText.Length-2, 2);
displayText.AppendLine("]");
return displayText.ToString();
}
///
/// Sets a specific item checked
///
///
///
public void SetItemChecked(int index, bool value)
{
checkedListBox.SetItemChecked(index, value);
}
///
/// Unchecks all items
///
public void UnCheckAll()
{
for (int i = 0; i < checkedListBox.Items.Count; i++)
{
checkedListBox.SetItemChecked(i, false);
}
}
///
/// Occurs if datasource is changed
///
public void OnDataSourceChanged(EventArgs e)
{
if (DataSourceChanged != null)
{
DataSourceChanged(this, e);
}
}
///
/// If the Default context menu is set to true, sets the context menu, else remove
///
///
private void SetContextMenu(bool enable)
{
if (checkedListBox.ContextMenu == null && enable)
{
ContextMenu contextMenu = new ContextMenu();
contextMenu.MenuItems.Add(checkAllText , delegate(object sender, EventArgs e) { CheckAll(); });
contextMenu.MenuItems.Add(uncheckAllText, delegate(object sender, EventArgs e) { UnCheckAll(); });
checkedListBox.ContextMenu = contextMenu;
}
if (!enable)
{
checkedListBox.ContextMenu = null;
}
}
protected override void OnDropDownOpening()
{
base.OnDropDownOpening();
if (popup == null)
{
popup = new ControlPopup(this, checkedListBox);
popup.PopupClosed += new EventHandler(PopupClosed);
popup.AddCloseKey(true, false, false, Keys.Up);
}
popup.Width = listWidth;
popup.Show();
}
private void PopupClosed(object sender,EventArgs empty)
{
Text = GetComboBoxText();
Invalidate();
}
#if DEBUG
public CheckedListBox Box
{
get { return checkedListBox; }
}
#endif
protected void OnDisplayMemberChanged(EventArgs e)
{
if (DisplayMemberChanged != null)
{
DisplayMemberChanged(this, e);
}
}
private void InitializeComponent()
{
this.SuspendLayout();
//
// CheckBoxCombo
//
this.AutoSize = true;
this.Name = "CheckBoxCombo";
this.Size = new System.Drawing.Size(305, 20);
this.ResumeLayout(false);
}
}
}
CheckBoxCombo
If you read my previous posts, you noticed the PopupControl and the Custom Combobox.
Now, it's time to fit it together in a CheckedListBox.
I start with deriving a class from CustomComboBox
The popup control will be shown if the dropdown action is triggered.
Override the OnDropDownOpening and add the popup and shows it. I also add a close key to close the popup with keyboard key ALT-UP. If, the popup is closed then, I will reset the ComboBox text with the selected items.
I add the CheckListBox control to the popup form. Because, I don't like doubleclicks, I set the CheckOnClick true;
The CheckedListBox does not contain DataSource capabilities. I have to implement it myself. The display text attribute is an attribute of an item object. This display text will be added to the CheckedListBox. I store the actual values in a Dictionary Object. With the CheckedIndices property of the CheckedListBox, I can resolve the value(s) of the selected item(s).
I also add a currency manager, to bind the control to a datasource. The datasource is an object, but with the right typeconverter it is more convenient to set it at design time. Notice, that I don't have a value member. This represents the item object itself.
The items in the CheckListBox, need to have the same index as the items in my private variable objectCollection. The DataBind() method fills the CheckedListBox items and the real object collection.
Now, it's time to fit it together in a CheckedListBox.
I start with deriving a class from CustomComboBox
public class CheckBoxCombo : CustomComboBox
{
}
The popup control will be shown if the dropdown action is triggered.
Override the OnDropDownOpening and add the popup and shows it. I also add a close key to close the popup with keyboard key ALT-UP. If, the popup is closed then, I will reset the ComboBox text with the selected items.
protected override void OnDropDownOpening()
{
base.OnDropDownOpening();
if (popup == null)
{
popup = new ControlPopup(this, checkedListBox);
popup.PopupClosed += new EventHandler(PopupClosed);
popup.AddCloseKey(true, false, false, Keys.Up);
}
popup.Width = listWidth;
popup.Show();
}
private void PopupClosed(object sender,EventArgs empty)
{
Text = GetComboBoxText();
Invalidate();
}
I add the CheckListBox control to the popup form. Because, I don't like doubleclicks, I set the CheckOnClick true;
checkedListBox.CheckOnClick = true;
The CheckedListBox does not contain DataSource capabilities. I have to implement it myself. The display text attribute is an attribute of an item object. This display text will be added to the CheckedListBox. I store the actual values in a Dictionary Object. With the CheckedIndices property of the CheckedListBox, I can resolve the value(s) of the selected item(s).
I also add a currency manager, to bind the control to a datasource. The datasource is an object, but with the right typeconverter it is more convenient to set it at design time. Notice, that I don't have a value member. This represents the item object itself.
private Dictionary objectCollection;
private CurrencyManager dataManager;
///
/// DataSource
///
[Bindable(true)]
[TypeConverter("System.Windows.Forms.Design.DataSourceConverter, System.Design")]
[Category("Data")]
[DefaultValue(null)]
public object DataSource
{
get
{
return dataSource;
}
set
{
dataSource = value;
DataBind();
OnDataSourceChanged(EventArgs.Empty);
}
}
private void DataBind()
{
propInfoItemDisplayMember = null;
propInfoItemsDisplayMember = null;
if (DataSource == null ||
base.BindingContext == null)
return;
CurrencyManager cm;
try
{
cm = base.BindingContext[this.DataSource] as CurrencyManager;
}
catch (ArgumentException)
{
// If no CurrencyManager was found
return;
}
//Other currency manager
if (this.dataManager != cm)
{
// Unwire the old CurrencyManager
if (this.dataManager != null)
{
this.dataManager.ListChanged -=
listChangedHandler;
this.dataManager.PositionChanged -=
positionChangedHandler;
}
checkedListBox.Items.Clear();
this.dataManager = cm;
// Wire the new CurrencyManager
if (this.dataManager != null)
{
this.dataManager.ListChanged +=
listChangedHandler;
this.dataManager.PositionChanged +=
positionChangedHandler;
}
// Update metadata and data
UpdateAllData();
}
}
The items in the CheckListBox, need to have the same index as the items in my private variable objectCollection. The DataBind() method fills the CheckedListBox items and the real object collection.
private void UpdateAllData()
{
checkedListBox.Items.Clear();
objectCollection.Clear();
for (int i = 0; i < DataManager.Count; i++)
{
objectCollection.Add(i, dataManager.List[i]);
AddListItem(dataManager.List[i]);
}
}
Wednesday, December 27, 2006
Custom ComboBox
Microsoft introduces more and more themesupport for (custom) controls. In Windows 2000, I used ControlPaint to draw my controls. In Windows XP, each control has got its own renderer. This renderer knows how to draw an control according any choosen XP theme. I create a custom ComboBox and found a good example at MSDN. I customized it and extended it to have better focus support . I have enter ALT-DOWN twice to get the drop list down. I added a focus rectangle and some focus support.
Here is my code
Here is my code
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
namespace MsDotnet.Windows.Forms
{
public class CustomComboBox : Control
{
// ContainsFocus --> ShowFocusCues
// ChangeUICues --> This is the event that is raised if Windows detects that some aspect of the focus or the focus cues may have changed
///
/// Occurs if the drop down is being opened
///
public EventHandler DropDownOpening;
///
/// Occurs if the drop down is being closed
///
public EventHandler DropDownClosing;
///
/// Paints the drop down control
///
public EventHandler PaintDropDownControl;
private Size arrowSize;
private Rectangle arrowRectangle;
private Rectangle topTextBoxRectangle;
private ComboBoxState textBoxState = ComboBoxState.Normal;
private ComboBoxState arrowState = ComboBoxState.Normal;
private bool isActivated = false;
public CustomComboBox()
: base()
{
this.Location = new Point(10, 10);
this.Size = new Size(140, 38);
this.Font = SystemFonts.IconTitleFont;
this.Text = String.Empty;
// Initialize the rectangles to look like the standard combo
// box control.
arrowSize = new Size(18, 20);
arrowRectangle = new Rectangle(ClientRectangle.X +
ClientRectangle.Width - arrowSize.Width - 1,
ClientRectangle.Y + 1,
arrowSize.Width,
arrowSize.Height);
topTextBoxRectangle = new Rectangle(ClientRectangle.X,
ClientRectangle.Y,
ClientRectangle.Width,
arrowSize.Height + 2);
}
protected override void OnChangeUICues(UICuesEventArgs e)
{
Invalidate();
base.OnChangeUICues(e);
}
protected override bool ProcessMnemonic(char charCode)
{
if (Enabled && Visible
&& IsMnemonic(charCode, this.Text))
{
// Perform action associated with mnemonic
// Moves focus to our control
Focus();
Invalidate();
return true;
}
return false;
}
///
/// Draw the combobox in the current state
///
///
protected override void OnPaint(PaintEventArgs e)
{
//base.OnPaint(e);
if (!ComboBoxRenderer.IsSupported)
{
return;
}
// Always draw the main text box and drop down arrow in their
// current states
ComboBoxRenderer.DrawTextBox(e.Graphics, topTextBoxRectangle,
Text, this.Font, textBoxState);
ComboBoxRenderer.DrawDropDownButton(e.Graphics, arrowRectangle,
arrowState);
if (ContainsFocus)
{
Rectangle focRect = topTextBoxRectangle;
focRect.Inflate(-2, -2);
ControlPaint.DrawFocusRectangle(e.Graphics, focRect);
}
// Only draw the bottom text box if the arrow has been clicked
if (isActivated)
{
OnPaintDropDownControl(e);
/*ComboBoxRenderer.DrawTextBox(e.Graphics,
bottomTextBoxRectangle, bottomText, this.Font,
textBoxState);*/
}
}
///
/// Occurs if the down arrow was pressed
///
///
protected virtual void OnPaintDropDownControl(PaintEventArgs e)
{
if (PaintDropDownControl != null)
{
PaintDropDownControl(this, e);
}
}
protected override void OnResize(EventArgs e)
{
topTextBoxRectangle.Width = ClientRectangle.Width;
arrowRectangle.X = ClientRectangle.X + ClientRectangle.Width - arrowRectangle.Width-1;
if (Height!=topTextBoxRectangle.Height)
{
Height = topTextBoxRectangle.Height;
}
base.OnResize(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
// Check whether the user clicked the arrow.
if (arrowRectangle.Contains(e.Location) &&
ComboBoxRenderer.IsSupported)
{
TriggerDropDown();
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.Down && e.Alt)
{
isActivated = false;
TriggerDropDown();
arrowState = ComboBoxState.Normal;
Invalidate();
}
base.OnKeyDown(e);
}
private void TriggerDropDown()
{
//Set the focus
if (!ContainsFocus)
{
Focus();
}
// Draw the arrow in the pressed state.
arrowState = ComboBoxState.Pressed;
// The user has activated the combo box.
if (!isActivated)
{
OnDropDownOpening();
textBoxState = ComboBoxState.Pressed;
isActivated = true;
}
// The user has deactivated the combo box.
else
{
OnDropDownClosing();
textBoxState = ComboBoxState.Normal;
isActivated = false;
}
// Redraw the control.
Invalidate();
}
protected virtual void OnDropDownClosing()
{
if (DropDownClosing != null)
{
DropDownClosing(this, EventArgs.Empty);
}
}
protected virtual void OnDropDownOpening()
{
if (DropDownOpening != null)
{
DropDownOpening(this, EventArgs.Empty);
}
}
protected override void OnGotFocus(EventArgs e)
{
Invalidate();
base.OnGotFocus(e);
}
protected override void OnLostFocus(EventArgs e)
{
Invalidate();
base.OnLostFocus(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
if (arrowRectangle.Contains(e.Location) &&
ComboBoxRenderer.IsSupported)
{
arrowState = ComboBoxState.Normal;
Invalidate();
}
}
}
}
Control propup
I was wondering how the combobox listbox shows up?
This seems to be a form like control. I googled on the internet and found a new Windows form popup control. This is part of .NET Framework 3.0. Because, I still use 2.0, there is no alternative. I found a suggestion to use a Toolstrip control. This control is a context menu control, that is able to host any control. But, it behaves like a context menu and therefore does not suite my needs. I decided to write a popup form that can show the control and close. BTW: I definitely not use the Infragistics popupcontainer. It stays showed, if another application is activated.
Here is the result.
I included a list of CloseKeys. I need my control to have keyboardsupport to close the popup. In my case. I needed ALT-UP to close the popup.
This seems to be a form like control. I googled on the internet and found a new Windows form popup control. This is part of .NET Framework 3.0. Because, I still use 2.0, there is no alternative. I found a suggestion to use a Toolstrip control. This control is a context menu control, that is able to host any control. But, it behaves like a context menu and therefore does not suite my needs. I decided to write a popup form that can show the control and close. BTW: I definitely not use the Infragistics popupcontainer. It stays showed, if another application is activated.
Here is the result.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace MsDotNet.Windows.Forms;
{
public class ControlPopup : Form
{
///
/// Occurs if the form is closed
///
public EventHandler PopupClosed;
#region member variables
public struct CloseKey
{
public bool Alt;
public bool Control;
public bool Shift;
public Keys KeyCode;
}
private Control control;
private List closeKeys=new List();
#endregion
#region properties
public List CloseKeys
{
get { return closeKeys; }
}
///
/// Popup control
///
public Control Control
{
get { return control; }
set
{
Controls.Clear();
control = value;
if (control != null)
{
Height = control.Height;
control.Leave += new EventHandler(PopForm_Leave);
control.KeyDown += new KeyEventHandler(OnControlKeyDown);
control.LostFocus += new EventHandler(control_LostFocus);
Controls.Add(control);
}
}
}
#endregion
#region ctor
///
/// Default constructor
///
public ControlPopup()
{
TopMost = true;
FormBorderStyle = FormBorderStyle.None;
ShowInTaskbar = false;
StartPosition = FormStartPosition.Manual;
}
///
/// Consturctor that adds the control and set the dockstyle of the control to Fill
///
///
///
public ControlPopup(Control owner, Control control)
: this()
{
Location = owner.PointToScreen(new Point(0, owner.Height));
Control = control;
control.Dock = DockStyle.Fill;
}
#endregion
///
/// Adds a popup close key
///
///
///
///
///
public void AddCloseKey(bool alt, bool shift, bool control, Keys key)
{
CloseKey closeKey = new CloseKey();
closeKey.Alt = alt;
closeKey.Shift = shift;
closeKey.Control = control;
closeKey.KeyCode = key;
closeKeys.Add(closeKey);
}
///
/// hides the popup form, does not close it.
///
private void OnHide()
{
if (this.Visible)
{
Hide();
}
if (PopupClosed != null)
{
PopupClosed(this, EventArgs.Empty);
}
}
protected override void OnLostFocus(EventArgs e)
{
if (!Control.Focused)
{
OnHide();
}
}
void control_LostFocus(object sender, EventArgs e)
{
OnHide();
}
void PopForm_Leave(object sender, EventArgs e)
{
OnHide();
}
protected void OnControlKeyDown(object sender,KeyEventArgs e)
{
foreach (CloseKey closeKey in closeKeys)
{
if (e.Alt == closeKey.Alt &&
e.Control == closeKey.Control &&
e.Shift == closeKey.Shift &&
e.KeyCode == closeKey.KeyCode)
{
OnHide();
}
}
}
private void InitializeComponent()
{
this.SuspendLayout();
//
// ControlPopup
//
this.ClientSize = new System.Drawing.Size(292, 262);
this.Name = "ControlPopup";
this.ResumeLayout(false);
}
}
}
I included a list of CloseKeys. I need my control to have keyboardsupport to close the popup. In my case. I needed ALT-UP to close the popup.
Wednesday, December 13, 2006
Customizing the DataGridView
Most people looking for the subject ends with the ASP.NET version of the control. I am wondering how the DataGridView of a windows form can be extended?
At MSDN an article was published how to host or create custom columns. Also changing the row appearance can be customized according to this article. At code project an article is published how to print content of the DataGridView control.
At MSDN an article was published how to host or create custom columns. Also changing the row appearance can be customized according to this article. At code project an article is published how to print content of the DataGridView control.
Multi column Combobox
Building your own ComboBox control is not as hard as it seems. There is already a ComboBox control available that can be fully customized. Add a class to your visual studio sulution and derive from the ComboBox class. You can make your own list of owner draw items. Set the DrawMode property to
DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable or OwnerDrawFixed. If the DrawMode is variable each item in the list has it's own height or with. If the Drawmode is Fixed each item has the same size and depends on the ItemWidth or ItemHeight property of the ComboBox.
With DrawMode is OwnerDrawVariable the OnMeasueItem has to be overriden to set the custom size of the item.
Override the OnDrawItem(DrawItemEventArgs e) event to draw the custom items.
To draw the custom list item the following help methods and properties are made available
e.Index // List item index, value of -1 is the selected item
e.DrawBackground() //Draws the background
e.DrawFocusRectangle(); //Draws a focus rectangle
e.Bounds; Canvas graphics size/Bounds
e.Graphics //Canvas graphics to paint the item
e.DrawItemState //State of the item: Checked, Focus, Selected, Grayed, Inactive etc..
If the item is a text item, use the DrawString to draw the text
e.Graphics.DrawString(text , Font, new SolidBrush(e.ForeColor), e.Bounds);
Use a string format to align the text drawn in the bounds.
e.g.
Examples
Color ComboBox
Image ComboBox
DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable or OwnerDrawFixed. If the DrawMode is variable each item in the list has it's own height or with. If the Drawmode is Fixed each item has the same size and depends on the ItemWidth or ItemHeight property of the ComboBox.
With DrawMode is OwnerDrawVariable the OnMeasueItem has to be overriden to set the custom size of the item.
protected override void OnMeasureItem(MeasureItemEventArgs e)
{
if (e.Index % 2 == 0)
{
e.ItemHeight = 20;
}
else
{
e.ItemHeight = 10;
}
e.ItemWidth = 50;
base.OnMeasureItem(e);
}
Override the OnDrawItem(DrawItemEventArgs e) event to draw the custom items.
To draw the custom list item the following help methods and properties are made available
e.Index // List item index, value of -1 is the selected item
e.DrawBackground() //Draws the background
e.DrawFocusRectangle(); //Draws a focus rectangle
e.Bounds; Canvas graphics size/Bounds
e.Graphics //Canvas graphics to paint the item
e.DrawItemState //State of the item: Checked, Focus, Selected, Grayed, Inactive etc..
If the item is a text item, use the DrawString to draw the text
e.Graphics.DrawString(text , Font, new SolidBrush(e.ForeColor), e.Bounds);
Use a string format to align the text drawn in the bounds.
e.g.
StringFormat format = new StringFormat();
format.Alignment = StringAlignment.Center; //Center text in the rectangle
e.Graphics.DrawString(value, Font, new SolidBrush(ForeColor),e.Bounds,format);
Examples
Color ComboBox
Image ComboBox
Subscribe to:
Posts (Atom)