Практическое руководство. Применение атрибутов к элементам управления Windows Forms
Для разработки компонентов и элементов управления, которые правильно взаимодействуют со средой разработки и правильно выполнять во время выполнения, необходимо правильно применять атрибуты к классам и членам.
Пример
В следующем примере кода демонстрируется использование нескольких атрибутов в пользовательский элемент управления. Элемент управления демонстрирует возможности простые операции ведения журнала. Когда элемент управления привязан к источнику данных, он отображает значения, отправленные источником данных в DataGridView элемента управления. Если значение превышает значение, заданное параметром Threshold
свойства ThresholdExceeded
события.
AttributesDemoControl
Записывает значения с LogEntry
класса. LogEntry
Класс — это класс шаблона, который означает, что он параметризован в типе, который он входит в систему. Например если AttributesDemoControl
записывает значения типа float
, каждая LogEntry
экземпляра объявляется и используется следующим образом.
// This method handles the timer's Elapsed event. It queries
// the performance counter for the next value, packs the
// value in a LogEntry object, and adds the new LogEntry to
// the list managed by the BindingSource.
private void timer1_Elapsed(
object sender,
System.Timers.ElapsedEventArgs e)
{
// Get the latest value from the performance counter.
float val = this.performanceCounter1.NextValue();
// The performance counter returns values of type float,
// but any type that implements the IComparable interface
// will work.
LogEntry<float> entry = new LogEntry<float>(val, DateTime.Now);
// Add the new LogEntry to the BindingSource list.
this.bindingSource1.Add(entry);
}
Note
Так как LogEntry
параметризован произвольным типом, он должен использовать отражение для работы с типом параметра. Функция порогового значения для работы, тип параметра T
должен реализовывать IComparable интерфейс.
Форма, содержащая AttributesDemoControl
периодически опрашивает счетчик производительности. Каждое значение упаковывается в LogEntry
соответствующего типа и добавления в форму BindingSource. AttributesDemoControl
Получает значение через свою привязку данных и отображает значение в DataGridView элемента управления.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Drawing;
using System.Data;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
// This sample demonstrates the use of various attributes for
// authoring a control.
namespace AttributesDemoControlLibrary
{
// This is the event handler delegate for the ThresholdExceeded event.
public delegate void ThresholdExceededEventHandler(ThresholdExceededEventArgs e);
// This control demonstrates a simple logging capability.
[ComplexBindingProperties("DataSource", "DataMember")]
[DefaultBindingProperty("TitleText")]
[DefaultEvent("ThresholdExceeded")]
[DefaultProperty("Threshold")]
[HelpKeywordAttribute(typeof(UserControl))]
[ToolboxItem("System.Windows.Forms.Design.AutoSizeToolboxItem,System.Design")]
public class AttributesDemoControl : UserControl
{
// This backs the Threshold property.
private object thresholdValue;
// The default fore color value for DataGridView cells that
// contain values that exceed the threshold.
private static Color defaultAlertForeColorValue = Color.White;
// The default back color value for DataGridView cells that
// contain values that exceed the threshold.
private static Color defaultAlertBackColorValue = Color.Red;
// The ambient color value.
private static Color ambientColorValue = Color.Empty;
// The fore color value for DataGridView cells that
// contain values that exceed the threshold.
private Color alertForeColorValue = defaultAlertForeColorValue;
// The back color value for DataGridView cells that
// contain values that exceed the threshold.
private Color alertBackColorValue = defaultAlertBackColorValue;
// Child controls that comprise this UserControl.
private TableLayoutPanel tableLayoutPanel1;
private DataGridView dataGridView1;
private Label label1;
// Required for designer support.
private System.ComponentModel.IContainer components = null;
// Default constructor.
public AttributesDemoControl()
{
InitializeComponent();
}
[Category("Appearance")]
[Description("The title of the log data.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Localizable(true)]
[HelpKeywordAttribute("AttributesDemoControlLibrary.AttributesDemoControl.TitleText")]
public string TitleText
{
get
{
return this.label1.Text;
}
set
{
this.label1.Text = value;
}
}
// The inherited Text property is hidden at design time and
// raises an exception at run time. This enforces a requirement
// that client code uses the TitleText property instead.
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text
{
get
{
throw new NotSupportedException();
}
set
{
throw new NotSupportedException();
}
}
[AmbientValue(typeof(Color), "Empty")]
[Category("Appearance")]
[DefaultValue(typeof(Color), "White")]
[Description("The color used for painting alert text.")]
public Color AlertForeColor
{
get
{
if (this.alertForeColorValue == Color.Empty &&
this.Parent != null)
{
return Parent.ForeColor;
}
return this.alertForeColorValue;
}
set
{
this.alertForeColorValue = value;
}
}
// This method is used by designers to enable resetting the
// property to its default value.
public void ResetAlertForeColor()
{
this.AlertForeColor = AttributesDemoControl.defaultAlertForeColorValue;
}
// This method indicates to designers whether the property
// value is different from the ambient value, in which case
// the designer should persist the value.
private bool ShouldSerializeAlertForeColor()
{
return (this.alertForeColorValue != AttributesDemoControl.ambientColorValue);
}
[AmbientValue(typeof(Color), "Empty")]
[Category("Appearance")]
[DefaultValue(typeof(Color), "Red")]
[Description("The background color for painting alert text.")]
public Color AlertBackColor
{
get
{
if (this.alertBackColorValue == Color.Empty &&
this.Parent != null)
{
return Parent.BackColor;
}
return this.alertBackColorValue;
}
set
{
this.alertBackColorValue = value;
}
}
// This method is used by designers to enable resetting the
// property to its default value.
public void ResetAlertBackColor()
{
this.AlertBackColor = AttributesDemoControl.defaultAlertBackColorValue;
}
// This method indicates to designers whether the property
// value is different from the ambient value, in which case
// the designer should persist the value.
private bool ShouldSerializeAlertBackColor()
{
return (this.alertBackColorValue != AttributesDemoControl.ambientColorValue);
}
[Category("Data")]
[Description("Indicates the source of data for the control.")]
[RefreshProperties(RefreshProperties.Repaint)]
[AttributeProvider(typeof(IListSource))]
public object DataSource
{
get
{
return this.dataGridView1.DataSource;
}
set
{
this.dataGridView1.DataSource = value;
}
}
[Category("Data")]
[Description("Indicates a sub-list of the data source to show in the control.")]
public string DataMember
{
get
{
return this.dataGridView1.DataMember;
}
set
{
this.dataGridView1.DataMember = value;
}
}
// This property would normally have its BrowsableAttribute
// set to false, but this code demonstrates using
// ReadOnlyAttribute, so BrowsableAttribute is true to show
// it in any attached PropertyGrid control.
[Browsable(true)]
[Category("Behavior")]
[Description("The timestamp of the latest entry.")]
[ReadOnly(true)]
public DateTime CurrentLogTime
{
get
{
int lastRowIndex =
this.dataGridView1.Rows.GetLastRow(
DataGridViewElementStates.Visible);
if (lastRowIndex > -1)
{
DataGridViewRow lastRow = this.dataGridView1.Rows[lastRowIndex];
DataGridViewCell lastCell = lastRow.Cells["EntryTime"];
return ((DateTime)lastCell.Value);
}
else
{
return DateTime.MinValue;
}
}
set
{
}
}
[Category("Behavior")]
[Description("The value above which the ThresholdExceeded event will be raised.")]
public object Threshold
{
get
{
return this.thresholdValue;
}
set
{
this.thresholdValue = value;
}
}
// This property exists only to demonstrate the
// PasswordPropertyText attribute. When this control
// is attached to a PropertyGrid control, the returned
// string will be displayed with obscuring characters
// such as asterisks. This property has no other effect.
[Category("Security")]
[Description("Demonstrates PasswordPropertyTextAttribute.")]
[PasswordPropertyText(true)]
public string Password
{
get
{
return "This is a demo password.";
}
}
// This property exists only to demonstrate the
// DisplayName attribute. When this control
// is attached to a PropertyGrid control, the
// property will be appear as "RenamedProperty"
// instead of "MisnamedProperty".
[Description("Demonstrates DisplayNameAttribute.")]
[DisplayName("RenamedProperty")]
public bool MisnamedProperty
{
get
{
return true;
}
}
// This is the declaration for the ThresholdExceeded event.
public event ThresholdExceededEventHandler ThresholdExceeded;
#region Implementation
// This is the event handler for the DataGridView control's
// CellFormatting event. Handling this event allows the
// AttributesDemoControl to examine the incoming log entries
// from the data source as they arrive.
//
// If the cell for which this event is raised holds the
// log entry's timestamp, the cell value is formatted with
// the full date/time pattern.
//
// Otherwise, the cell's value is assumed to hold the log
// entry value. If the value exceeds the threshold value,
// the cell is painted with the colors specified by the
// AlertForeColor and AlertBackColor properties, after which
// the ThresholdExceeded is raised. For this comparison to
// succeed, the log entry's type must implement the IComparable
// interface.
private void dataGridView1_CellFormatting(
object sender,
DataGridViewCellFormattingEventArgs e)
{
try
{
if (e.Value != null)
{
if (e.Value is DateTime)
{
// Display the log entry time with the
// full date/time pattern (long time).
e.CellStyle.Format = "F";
}
else
{
// Scroll to the most recent entry.
DataGridViewRow row = this.dataGridView1.Rows[e.RowIndex];
DataGridViewCell cell = row.Cells[e.ColumnIndex];
this.dataGridView1.FirstDisplayedCell = cell;
if (this.thresholdValue != null)
{
// Get the type of the log entry.
object val = e.Value;
Type paramType = val.GetType();
// Compare the log entry value to the threshold value.
// Use reflection to call the CompareTo method on the
// template parameter's type.
int compareVal = (int)paramType.InvokeMember(
"CompareTo",
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
e.Value,
new object[] { this.thresholdValue },
System.Globalization.CultureInfo.InvariantCulture);
// If the log entry value exceeds the threshold value,
// set the cell's fore color and back color properties
// and raise the ThresholdExceeded event.
if (compareVal > 0)
{
e.CellStyle.BackColor = this.alertBackColorValue;
e.CellStyle.ForeColor = this.alertForeColorValue;
ThresholdExceededEventArgs teea =
new ThresholdExceededEventArgs(
this.thresholdValue,
e.Value);
this.ThresholdExceeded(teea);
}
}
}
}
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
}
}
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.label1 = new System.Windows.Forms.Label();
this.tableLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.AutoSize = true;
this.tableLayoutPanel1.ColumnCount = 1;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 100F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 100F));
this.tableLayoutPanel1.Controls.Add(this.dataGridView1, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(10, 10);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(10);
this.tableLayoutPanel1.RowCount = 2;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 80F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(425, 424);
this.tableLayoutPanel1.TabIndex = 0;
//
// dataGridView1
//
this.dataGridView1.AllowUserToAddRows = false;
this.dataGridView1.AllowUserToDeleteRows = false;
this.dataGridView1.AllowUserToOrderColumns = true;
this.dataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.AutoSizeRowsMode = System.Windows.Forms.DataGridViewAutoSizeRowsMode.AllCells;
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Control;
dataGridViewCellStyle1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
this.dataGridView1.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
this.dataGridView1.ColumnHeadersHeight = 4;
this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.dataGridView1.Location = new System.Drawing.Point(13, 57);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.ReadOnly = true;
this.dataGridView1.RowHeadersVisible = false;
this.dataGridView1.Size = new System.Drawing.Size(399, 354);
this.dataGridView1.TabIndex = 1;
this.dataGridView1.CellFormatting += new System.Windows.Forms.DataGridViewCellFormattingEventHandler(this.dataGridView1_CellFormatting);
//
// label1
//
this.label1.AutoSize = true;
this.label1.BackColor = System.Drawing.SystemColors.Control;
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
this.label1.Location = new System.Drawing.Point(13, 13);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(399, 38);
this.label1.TabIndex = 2;
this.label1.Text = "label1";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// AttributesDemoControl
//
this.Controls.Add(this.tableLayoutPanel1);
this.Name = "AttributesDemoControl";
this.Padding = new System.Windows.Forms.Padding(10);
this.Size = new System.Drawing.Size(445, 444);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
}
// This is the EventArgs class for the ThresholdExceeded event.
public class ThresholdExceededEventArgs : EventArgs
{
private object thresholdValue = null;
private object exceedingValue = null;
public ThresholdExceededEventArgs(
object thresholdValue,
object exceedingValue)
{
this.thresholdValue = thresholdValue;
this.exceedingValue = exceedingValue;
}
public object ThresholdValue
{
get
{
return this.thresholdValue;
}
}
public object ExceedingValue
{
get
{
return this.exceedingValue;
}
}
}
// This class encapsulates a log entry. It is a parameterized
// type (also known as a template class). The parameter type T
// defines the type of data being logged. For threshold detection
// to work, this type must implement the IComparable interface.
[TypeConverter("LogEntryTypeConverter")]
public class LogEntry<T> where T : IComparable
{
private T entryValue;
private DateTime entryTimeValue;
public LogEntry(
T value,
DateTime time)
{
this.entryValue = value;
this.entryTimeValue = time;
}
public T Entry
{
get
{
return this.entryValue;
}
}
public DateTime EntryTime
{
get
{
return this.entryTimeValue;
}
}
// This is the TypeConverter for the LogEntry class.
public class LogEntryTypeConverter : TypeConverter
{
public override bool CanConvertFrom(
ITypeDescriptorContext context,
Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(
ITypeDescriptorContext context,
System.Globalization.CultureInfo culture,
object value)
{
if (value is string)
{
string[] v = ((string)value).Split(new char[] { '|' });
Type paramType = typeof(T);
T entryValue = (T)paramType.InvokeMember(
"Parse",
BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod,
null,
null,
new string[] { v[0] },
culture);
return new LogEntry<T>(
entryValue,
DateTime.Parse(v[2]));
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(
ITypeDescriptorContext context,
System.Globalization.CultureInfo culture,
object value,
Type destinationType)
{
if (destinationType == typeof(string))
{
LogEntry<T> le = value as LogEntry<T>;
string stringRepresentation =
String.Format("{0} | {1}",
le.Entry,
le.EntryTime);
return stringRepresentation;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using AttributesDemoControlLibrary;
// This sample demonstrates using the AttributesDemoControl to log
// data from a data source.
namespace AttributesDemoControlTest
{
public class Form1 : Form
{
private BindingSource bindingSource1;
private System.Diagnostics.PerformanceCounter performanceCounter1;
private Button startButton;
private Button stopButton;
private System.Timers.Timer timer1;
private ToolStripStatusLabel statusStripPanel1;
private NumericUpDown numericUpDown1;
private GroupBox groupBox1;
private GroupBox groupBox2;
private TableLayoutPanel tableLayoutPanel1;
private AttributesDemoControl attributesDemoControl1;
private System.ComponentModel.IContainer components = null;
// This form uses an AttributesDemoControl to display a stream
// of LogEntry objects. The data stream is generated by polling
// a performance counter and communicating the counter values
// to the control with data binding.
public Form1()
{
InitializeComponent();
// Set the initial value of the threshold up/down control
// to the control's threshold value.
this.numericUpDown1.Value =
(decimal)(float)this.attributesDemoControl1.Threshold;
// Assign the performance counter's name to the control's
// title text.
this.attributesDemoControl1.TitleText =
this.performanceCounter1.CounterName;
}
// This method handles the ThresholdExceeded event. It posts
// the value that exceeded the threshold to the status strip.
private void attributesDemoControl1_ThresholdExceeded(
ThresholdExceededEventArgs e)
{
string msg = String.Format(
"{0}: Value {1} exceeded threshold {2}",
this.attributesDemoControl1.CurrentLogTime,
e.ExceedingValue,
e.ThresholdValue);
this.ReportStatus( msg );
}
// This method handles the timer's Elapsed event. It queries
// the performance counter for the next value, packs the
// value in a LogEntry object, and adds the new LogEntry to
// the list managed by the BindingSource.
private void timer1_Elapsed(
object sender,
System.Timers.ElapsedEventArgs e)
{
// Get the latest value from the performance counter.
float val = this.performanceCounter1.NextValue();
// The performance counter returns values of type float,
// but any type that implements the IComparable interface
// will work.
LogEntry<float> entry = new LogEntry<float>(val, DateTime.Now);
// Add the new LogEntry to the BindingSource list.
this.bindingSource1.Add(entry);
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
this.attributesDemoControl1.Threshold =
(float)this.numericUpDown1.Value;
string msg = String.Format(
"Threshold changed to {0}",
this.attributesDemoControl1.Threshold);
this.ReportStatus(msg);
}
private void startButton_Click(object sender, EventArgs e)
{
this.ReportStatus(DateTime.Now + ": Starting");
this.timer1.Start();
}
private void stopButton_Click(object sender, EventArgs e)
{
this.ReportStatus(DateTime.Now + ": Stopping");
this.timer1.Stop();
}
private void ReportStatus(string msg)
{
if (msg != null)
{
this.statusStripPanel1.Text = msg;
}
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.bindingSource1 = new System.Windows.Forms.BindingSource(this.components);
this.performanceCounter1 = new System.Diagnostics.PerformanceCounter();
this.startButton = new System.Windows.Forms.Button();
this.stopButton = new System.Windows.Forms.Button();
this.timer1 = new System.Timers.Timer();
this.statusStripPanel1 = new System.Windows.Forms.ToolStripStatusLabel();
this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.attributesDemoControl1 = new AttributesDemoControlLibrary.AttributesDemoControl();
((System.ComponentModel.ISupportInitialize)(this.bindingSource1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.performanceCounter1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.timer1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// performanceCounter1
//
this.performanceCounter1.CategoryName = ".NET CLR Memory";
this.performanceCounter1.CounterName = "Gen 0 heap size";
this.performanceCounter1.InstanceName = "_Global_";
//
// startButton
//
this.startButton.Location = new System.Drawing.Point(31, 25);
this.startButton.Name = "startButton";
this.startButton.TabIndex = 1;
this.startButton.Text = "Start";
this.startButton.Click += new System.EventHandler(this.startButton_Click);
//
// stopButton
//
this.stopButton.Location = new System.Drawing.Point(112, 25);
this.stopButton.Name = "stopButton";
this.stopButton.TabIndex = 2;
this.stopButton.Text = "Stop";
this.stopButton.Click += new System.EventHandler(this.stopButton_Click);
//
// timer1
//
this.timer1.Interval = 1000;
this.timer1.SynchronizingObject = this;
this.timer1.Elapsed += new System.Timers.ElapsedEventHandler(this.timer1_Elapsed);
//
// statusStripPanel1
//
this.statusStripPanel1.BorderStyle = System.Windows.Forms.Border3DStyle.SunkenOuter;
this.statusStripPanel1.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
this.statusStripPanel1.Name = "statusStripPanel1";
this.statusStripPanel1.Text = "Ready";
//
// numericUpDown1
//
this.numericUpDown1.Location = new System.Drawing.Point(37, 29);
this.numericUpDown1.Maximum = new decimal(new int[] {
1410065408,
2,
0,
0});
this.numericUpDown1.Name = "numericUpDown1";
this.numericUpDown1.TabIndex = 7;
this.numericUpDown1.ValueChanged += new System.EventHandler(this.numericUpDown1_ValueChanged);
//
// groupBox1
//
this.groupBox1.Anchor = System.Windows.Forms.AnchorStyles.None;
this.groupBox1.Controls.Add(this.numericUpDown1);
this.groupBox1.Location = new System.Drawing.Point(280, 326);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(200, 70);
this.groupBox1.TabIndex = 13;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Threshold Value";
//
// groupBox2
//
this.groupBox2.Anchor = System.Windows.Forms.AnchorStyles.None;
this.groupBox2.Controls.Add(this.startButton);
this.groupBox2.Controls.Add(this.stopButton);
this.groupBox2.Location = new System.Drawing.Point(26, 327);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(214, 68);
this.groupBox2.TabIndex = 14;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Logging";
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 2;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.Controls.Add(this.groupBox2, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.groupBox1, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.attributesDemoControl1, 0, 0);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(10);
this.tableLayoutPanel1.RowCount = 2;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 80F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(514, 411);
this.tableLayoutPanel1.TabIndex = 15;
//
// attributesDemoControl1
//
this.tableLayoutPanel1.SetColumnSpan(this.attributesDemoControl1, 2);
this.attributesDemoControl1.DataMember = "";
this.attributesDemoControl1.DataSource = this.bindingSource1;
this.attributesDemoControl1.Dock = System.Windows.Forms.DockStyle.Fill;
this.attributesDemoControl1.Location = new System.Drawing.Point(13, 13);
this.attributesDemoControl1.Name = "attributesDemoControl1";
this.attributesDemoControl1.Padding = new System.Windows.Forms.Padding(10);
this.attributesDemoControl1.Size = new System.Drawing.Size(488, 306);
this.attributesDemoControl1.TabIndex = 0;
this.attributesDemoControl1.Threshold = 200000F;
this.attributesDemoControl1.TitleText = "TITLE";
this.attributesDemoControl1.ThresholdExceeded += new AttributesDemoControlLibrary.ThresholdExceededEventHandler(this.attributesDemoControl1_ThresholdExceeded);
//
// Form1
//
this.BackColor = System.Drawing.SystemColors.Control;
this.ClientSize = new System.Drawing.Size(514, 430);
this.Controls.Add(this.tableLayoutPanel1);
this.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.bindingSource1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.performanceCounter1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.timer1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
this.groupBox1.ResumeLayout(false);
this.groupBox2.ResumeLayout(false);
this.tableLayoutPanel1.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
}
}
В первом примере кода — AttributesDemoControl
реализации. Во втором примере кода демонстрируется форму, которая использует AttributesDemoControl
.
Атрибуты уровня класса
Некоторые атрибуты применяются на уровне класса. В следующем примере кода показаны атрибуты, которые обычно применяются к элементу управления Windows Forms.
// This control demonstrates a simple logging capability.
[ComplexBindingProperties("DataSource", "DataMember")]
[DefaultBindingProperty("TitleText")]
[DefaultEvent("ThresholdExceeded")]
[DefaultProperty("Threshold")]
[HelpKeywordAttribute(typeof(UserControl))]
[ToolboxItem("System.Windows.Forms.Design.AutoSizeToolboxItem,System.Design")]
public class AttributesDemoControl : UserControl
{
Атрибут TypeConverter
TypeConverterAttribute является еще одним часто используемые атрибутом уровня класса. В следующем примере кода показано его использование для LogEntry
класса. В этом примере также показана реализация TypeConverter для LogEntry
тип с именем LogEntryTypeConverter
.
// This class encapsulates a log entry. It is a parameterized
// type (also known as a template class). The parameter type T
// defines the type of data being logged. For threshold detection
// to work, this type must implement the IComparable interface.
[TypeConverter("LogEntryTypeConverter")]
public class LogEntry<T> where T : IComparable
{
private T entryValue;
private DateTime entryTimeValue;
public LogEntry(
T value,
DateTime time)
{
this.entryValue = value;
this.entryTimeValue = time;
}
public T Entry
{
get
{
return this.entryValue;
}
}
public DateTime EntryTime
{
get
{
return this.entryTimeValue;
}
}
// This is the TypeConverter for the LogEntry class.
public class LogEntryTypeConverter : TypeConverter
{
public override bool CanConvertFrom(
ITypeDescriptorContext context,
Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(
ITypeDescriptorContext context,
System.Globalization.CultureInfo culture,
object value)
{
if (value is string)
{
string[] v = ((string)value).Split(new char[] { '|' });
Type paramType = typeof(T);
T entryValue = (T)paramType.InvokeMember(
"Parse",
BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod,
null,
null,
new string[] { v[0] },
culture);
return new LogEntry<T>(
entryValue,
DateTime.Parse(v[2]));
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(
ITypeDescriptorContext context,
System.Globalization.CultureInfo culture,
object value,
Type destinationType)
{
if (destinationType == typeof(string))
{
LogEntry<T> le = value as LogEntry<T>;
string stringRepresentation =
String.Format("{0} | {1}",
le.Entry,
le.EntryTime);
return stringRepresentation;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
}
Атрибуты на уровне элемента
Некоторые атрибуты применяются на уровне членов. В следующих примерах кода некоторые атрибуты, которые обычно применяются к свойствам элементов управления Windows Forms.
[Category("Appearance")]
[Description("The title of the log data.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Localizable(true)]
[HelpKeywordAttribute("AttributesDemoControlLibrary.AttributesDemoControl.TitleText")]
public string TitleText
{
get
{
return this.label1.Text;
}
set
{
this.label1.Text = value;
}
}
Атрибут AmbientValue
В следующем примере демонстрируется AmbientValueAttribute ; содержит код, поддерживающий взаимодействие со средой разработки. Это взаимодействие называется окружением.
[AmbientValue(typeof(Color), "Empty")]
[Category("Appearance")]
[DefaultValue(typeof(Color), "White")]
[Description("The color used for painting alert text.")]
public Color AlertForeColor
{
get
{
if (this.alertForeColorValue == Color.Empty &&
this.Parent != null)
{
return Parent.ForeColor;
}
return this.alertForeColorValue;
}
set
{
this.alertForeColorValue = value;
}
}
// This method is used by designers to enable resetting the
// property to its default value.
public void ResetAlertForeColor()
{
this.AlertForeColor = AttributesDemoControl.defaultAlertForeColorValue;
}
// This method indicates to designers whether the property
// value is different from the ambient value, in which case
// the designer should persist the value.
private bool ShouldSerializeAlertForeColor()
{
return (this.alertForeColorValue != AttributesDemoControl.ambientColorValue);
}
Атрибуты привязки данных
В следующих примерах показано реализацию сложную привязку данных. Уровня класса ComplexBindingPropertiesAttribute, показанный ранее, указывает DataSource
и DataMember
свойства, используемые для привязки данных. AttributeProviderAttribute Указывает тип, к которому DataSource
будет привязано свойство.
[Category("Data")]
[Description("Indicates the source of data for the control.")]
[RefreshProperties(RefreshProperties.Repaint)]
[AttributeProvider(typeof(IListSource))]
public object DataSource
{
get
{
return this.dataGridView1.DataSource;
}
set
{
this.dataGridView1.DataSource = value;
}
}
[Category("Data")]
[Description("Indicates a sub-list of the data source to show in the control.")]
public string DataMember
{
get
{
return this.dataGridView1.DataMember;
}
set
{
this.dataGridView1.DataMember = value;
}
}
Компиляция кода
- Форма, содержащая
AttributesDemoControl
необходима ссылка наAttributesDemoControl
сборки для сборки.