How do I add a custom tab to the property grid when it is displaying my object’s properties?
We have a small sample that shows how to do this. Download PropTab.zip. After you download and unzip the sample, build the project. Both the control assembly and a small driver assembly get built. After that add the control to your toolbox using ’Customise toolbox…’. Then drag and drop an instance of the added control onto the form in the driver winforms sub-project. When you select this control the properties window should have a tab with a bitmap ’T’ as shown below. These are the steps involved. Before following these steps please download and take a look at the sample. That will greatly help when following these steps. Control related steps Assume that you have a control that has two sets of properties, one set that you wish to have displayed in the main property tab and another set that you wish to have displayed in the second tab. Mark those properties that you wish to display in the first tab with the BrowsableAttribute to true. Mark those properties that you wish to display in the second tab with the BrowsableAttribute set to false. Create another attribute. Name it anything you want and give it a single boolean property. Initialize this property to true. Other steps Derive a class from System.Windows.Forms.PropertyGridInternal.PropertiesTab. You have to override a few methods. The most important of these is GetProperties. We override GetProperties as shown below to use our CustomAttribute as the filtering attribute instead of the BrowsableAttribute that the PropertyGrid uses by default. public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object component, Attribute[] attrs) { return TypeDescriptor.GetProperties(component, new Attribute[] {new BrowsableAttribute(false), new CustomTabDisplayAttribute(true)}); } Create a embedded resource bitmap with the same name as the derived tab’s type. This bitmap had to be 16×16. A brief note of explanation on the sample. The sample shows a user control that displays its own tab for some properties. These properties are marked with the filtering attribute, CustomTabDisplayAttribute. The rest of the properties are just displayed in the normal property tab and need no special attention. To get a deeper understanding of how this works, please refer to these FAQs on TypeConverters and TypeDescriptors. TypeDescriptors TypeConverters
What is the function of TypeConverters?
Type converters let you convert one type to another type. Each type that you declare can optionally have a TypeConverter associated with it using the TypeConverterAttribute. If you do not specify one the class will inherit a TypeConverter from its base class. The following methods deal with the type conversion work that is performed by TypeConverters. // for conversion from another type to the type that this type converter is associated with public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType); public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value); // for conversion of this type to some other type public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType); public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType); The above functions provide the core of TypeConverters. One reason for the confusion surrounding TypeConverters is the fact that they have other functions that are unrelated to the primary type conversion function. Methods such as public PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value) do not perform type conversion. They are present for another purpose. Typically when we require access to the properties, events and methods we use a TypeDescriptor. However there are .NET framework elements such as the PropertyGrid that first access the TypeConverter and then query it for a list of Properties (it returns true when public bool GetPropertiesSupported(); is called). If the TypeConverter returns false from public bool GetPropertiesSupported(), then the TypeDescriptor is queried for such information. Deriving a type converter is an easy way to present properties, events etc in any manner that you want especially with the property grid. In your own code also when you access Property information it is good practice to query the TypeConverter first. So, presentation of object properties, methods and events is also a function of the TypeConverter. Unfortunately, the name ’TypeConverter’ does not hint at this function. Enclosed is a small sample that illustrates the use of a custom Type Converter for conversion. Download TypeConverter.zip. Try the sample and it will be clear what Type Converters primarily do. For more information on TypeDescriptors please refer to https://www.syncfusion.com/content/en-us/faq/windowsforms/search/705.aspx
How can I specially color only the currentcell of my readonly datagrid
You can use the first technique listed in this FAQ: How do I color an individual cell depending upon its value or some external method? The idea is to derive a custom columnstyle. override its Paint method to specially color the background of the currentcell. Also, override the Edit to avoid the current cell becoming active. Below is a code snippet showing how you can do this. You can also download samples(C#, VB). Public Class DataGridColoredTextBoxColumn Inherits DataGridTextBoxColumn Private column As Integer ’ column where this columnstyle is located… Public Sub New() column = -2 End Sub Protected Overloads Overrides Sub Paint(ByVal g As Graphics, ByVal bounds As Rectangle, ByVal source As CurrencyManager, ByVal rowNum As Integer, ByVal backBrush As Brush, ByVal foreBrush As Brush, ByVal alignToRight As Boolean) Try Dim grid As DataGrid = Me.DataGridTableStyle.DataGrid ’first time set the column properly If column = -2 Then Dim i As Integer i = Me.DataGridTableStyle.GridColumnStyles.IndexOf(Me) If i > -1 Then column = i End If End If If grid.CurrentRowIndex = rowNum And grid.CurrentCell.ColumnNumber = column Then backBrush = New LinearGradientBrush(bounds, Color.FromArgb(255, 200, 200), Color.FromArgb(128, 20, 20), LinearGradientMode.BackwardDiagonal) foreBrush = New SolidBrush(Color.White) End If Catch ex As Exception ’ empty catch Finally ’ make sure the base class gets called to do the drawing with ’ the possibly changed brushes MyBase.Paint(g, bounds, source, rowNum, backBrush, foreBrush, alignToRight) End Try End Sub Protected Overloads Overrides Sub Edit(ByVal source As System.Windows.Forms.CurrencyManager, ByVal rowNum As Integer, ByVal bounds As System.Drawing.Rectangle, ByVal [readOnly] As Boolean, ByVal instantText As String, ByVal cellIsVisible As Boolean) ’do nothing… don’t call the basecalss End Sub End Class
How can I prevent a particular cell from being editable
You can do this by deriving a custom column style and overriding its virtual Edit member. Below is an override that will prevent the cell in row 1 of the column from getting the edit focus. You can paste this code in the DataGridDigitsTextBoxColumn sample to see it work. If you want a more flexible solution, you could expose an event as part of your derived columnstyle that fires right before the call to the baseclass in the Edit override. This would allow the handler of the event to set the enable value depending upon the row and column parameters that are passed as part of the event args. You can download a sample (C#, VB) that implements this technique. The sample also fires the event right before painting the cell to decide whether to paint a gray background for the disabled cell. You could modify the eventargs to include a backcolor, and use this event to color cells based on row and column values. //this override will prevent the cell in row 1 from getting the edit focus protected override void Edit(System.Windows.Forms.CurrencyManager source, int rowNum, System.Drawing.Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible) { if(rowNum == 1) return; base.Edit(source, rowNum, bounds, readOnly, instantText, cellIsVisible); }
How do I prevent sorting a single column in my DataGrid
You can do this by deriving the DataGrid and overriding OnMouseDown. In your override, do a HitText and if the hit is on a column header that you do not want to sort, do not call the baseclass. Here is a code that sorts all columns except the second column. [C#] //derived class public class MyDataGrid : DataGrid { protected override void OnMouseDown(MouseEventArgs e) { Point pt = new Point(e.X, e.Y); DataGrid.HitTestInfo hti = this.HitTest(pt); if (hti.Type == HitTestType.ColumnHeader && hti.Column == 1) { //don’t sort col 1 return; //don’t call baseclass } base.OnMouseDown(e); } } [VB.NET] ‘derived class Public Class MyDataGrid Inherits DataGrid Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs) Dim pt As New Point(e.X, e.Y) Dim hti As DataGrid.HitTestInfo = Me.HitTest(pt) If hti.Type = HitTestType.ColumnHeader AndAlso hti.Column = 1 Then ‘don’t sort col 1 Return ‘don’t call baseclass End If MyBase.OnMouseDown(e) End Sub ‘OnMouseDown End Class ‘MyDataGrid