|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionDuring my latest project, I needed a Part 1: Databinding the ListView, creating columns and sortersThe databinding part of my ' this.listView1.DataTable = CreateDataTable1( );
this.listView1.DataBind( );
Upon calling the setter for private System.Data.DataTable _dataTable;
[ Bindable ( true),
Category ( "Whoua.Src"),
Description ( "DataTable")]
public System.Data.DataTable DataTable
{
get{ return( _dataTable); }
set
{
if( _dataTable == value)
{
return;
}
_dataTable = value;
this.CreateListViewColumns( _dataTable);
}
}
ColumnHeader[] columnHeaders = new ColumnHeader[ dataTable.Columns.Count];
System.Windows.Forms.ColumnHeader columnHeader = null;
this.Columns.Clear( );
// --- Enumerate DataColumns and create ColumnHeaders for them (20050418 SDE)
int i = 0;
foreach( System.Data.DataColumn dataColumn in dataTable.Columns)
{
columnHeader = getSortableListviewColumnHeader( dataColumn);
columnHeader.Text = dataColumn.ColumnName;
columnHeader.TextAlign = HorizontalAlignment.Left;
columnHeaders[ i] = columnHeader;
i++;
}
// --- Tell listview to create the columns (20050309 SDE)
this.Columns.AddRange( columnHeaders);
Nothing fancy going on over here, except that a call to I read the excellent article of Eddie Velasquez on implementing sorting for a The first step in setting up sorting is performed by SortableListviewColumnHeader sortableListviewColumnHeader =
new SortableListviewColumnHeader( );
System.Type type = dataColumn.DataType;
if( type == typeof(System.String))
{
sortableListviewColumnHeader.ListviewSorter =
new ListViewTextCaseInsensitiveSorter( );
return( sortableListviewColumnHeader);
}
else if( type == typeof( System.Int32))
{
sortableListviewColumnHeader.ListviewSorter =
new ListViewInt32Sorter( );
return( sortableListviewColumnHeader);
}
//etc..
Whenever a column is clicked, the ' this.ColumnClick += new ColumnClickEventHandler( ListView_ColumnClick);
private void ListView_ColumnClick( object sender, ColumnClickEventArgs e)
{
// --- Perform sorting
System.Windows.Forms.ListView listview = sender as ListView;
SortableListviewColumnHeader sorter =
listview.Columns[ e.Column] as SortableListviewColumnHeader;
if( listview.Sorting == SortOrder.None)
{
listview.Sorting = SortOrder.Ascending;
}
else if( listview.Sorting == SortOrder.Ascending)
{
listview.Sorting = SortOrder.Descending;
}
else
{
listview.Sorting = SortOrder.Ascending;
}
sorter.Column = e.Column;
this.ListViewItemSorter = sorter;
}
The data is self created by calling
Part 2: Autofit contentsYou can tell a foreach( System.Windows.Forms.ColumnHeader c in this.listView1.Columns)
{
c.Width = -2;
}
You need to do this after the list items have been created.
Using option -2 seems like a good choice, but it isn't. Consider a user changing the width of a column because he doesn't need to see a certain column. Whenever data in the In my solution, I'm calculating the width of each item using code from Pierre Arnaud's article. private void Data2Listview( System.Data.DataTable dt)
{
System.Diagnostics.Debug.Assert( dt.Columns.Count == this.Columns.Count,
string.Format( "Columncount != listview columncount"));
System.Windows.Forms.ListViewItem listViewItem = null;
// --- Add a ListView-items for each row
// and see if it has the largest string-length
// of items so we can fit the columnheader (20050228 SDE)
Graphics g = this.CreateGraphics( );
string item = string.Empty;
foreach( System.Data.DataRow dr in dt.Rows)
{
int i = 0; // --- Enumerating the columns (20050515 SDE)
ArrayList items = new ArrayList( );
SortableListviewColumnHeader slc = null;
float itemWidth = 0.0F;
float columnWidth = 0.0F;
float width = 0.0F;
int itemLength = 0;
foreach( System.Data.DataColumn dc in dt.Columns)
{
item = dr[ dc].ToString().Trim();
items.Add( item);
slc = (SortableListviewColumnHeader) this.Columns[ i];
// --- If the widht of a columnheader
// is larger then the largest item in the
// list, we use the columnheader (20050515 SDE)
columnWidth = MeasureDisplayStringWidth( g,
slc.Text, this.Font);
// --- Length item (20050515 SDE)
itemLength = item.Length;
if( item.Trim() != string.Empty)
{
itemWidth = MeasureDisplayStringWidth( g,
item, this.Font);
if( itemWidth > columnWidth)
{
width = itemWidth;
}
else
{
width = columnWidth;
}
if( width > slc.LargestSize)
{
slc.LargestSize = width;
}
}
// --- Use columnwidth when values are null (20050515 SDE)
else
{
width = columnWidth;
if( width > slc.LargestSize)
{
slc.LargestSize = width;
}
}
i++;
}
string[] listItems = (string []) items.ToArray( typeof( string));
listViewItem = new ListViewItem( listItems);
this.Items.Add( listViewItem);
}
}
After private void AdjustColumnWidths( )
{
string s = string.Empty;
foreach( SortableListviewColumnHeader slc in this.Columns)
{
// --- If the PreviousWidth equals
// the Width, the user hasn't modified a columns
// width and we need to autofit
// it to the largest item. Otherwise,
// PreviousWidth is not equal
// to the width, the user has modified the width
// of a column, and we need to leave
// it the way it is (20050515 SDE)
if( slc.PreviousWidth == slc.Width || slc.PreviousWidth == 0)
{
slc.Width = System.Convert.ToInt32( slc.LargestSize);
slc.PreviousWidth = slc.Width;
}
}
}
This is all what is needed to bypass the shortcomings of the standard When using this
You can see the the columns either fit the width of their largest item (Date of Birth, Name, City & ZIP), or the width of the column header (Employee # & Weight). If you select the button 'Update ds1', the
If a user would adjust the size of the 'City' column before pressing the Update button, you would see the following picture:
The width isn't adjusted anymore, just like you would expect.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||