NET User Interfaces in Csharp Windows Forms and Custom Controls [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

NET User Interfaces in Csharp Windows Forms and Custom Controls [Electronic resources] - نسخه متنی

Matthew MacDonald

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید



























A Simple Graphing Control


The last control considered here is a simple bar chart. It's a good demonstration of how you can create a higher-level GDI+ control. Instead of representing a single shape or button, it renders a complete display according to the supplied data.

The basis of the chart is a BarItem class that stores information for a single bar. This information consists of a numerical value and a short title that can be displayed along with the bar.


public class BarItem
{
public string ShortForm;
public decimal Value;
public BarItem(string shortForm, decimal value)
{
this.ShortForm = shortForm;
this.Value = value;
}
}

The data for a bar chart is made up of a collection of BarItem objects. Thus, to support the control you can create a strongly typed collection that only accepts BarItem objects. You could use an ordinary ArrayList or Hashtable collection with the control, but you would not be able to prevent the user from adding invalid objects to the chart data.


public class BarItemCollection : CollectionBase
{
public void Add(BarItem item)
{
this.List.Add(item);
}
public void Remove(int index)
{
// Check to see if there is an item at the supplied index.
if ((index > Count - 1) || (index < 0 ))
{
throw new System.IndexOutOfRangeException();
}
else
{
this.List.RemoveAt(index);
}
}
public BarItem Item(int index)
{
// The appropriate item is retrieved from the List object and
// explicitly cast to the BarItem type.
return (BarItem)this.List[index];
}
}

The SimpleChart control provides a BarItemCollection through its Bars property. The client programmer must create and add the appropriate BarItem objects. A more sophisticated control might add dedicated UITypeEditors that allow BarItem objects to be created and added at design time.



public class SimpleChart : System.Windows.Forms.UserControl
{
private BarItemCollection bars = new BarItemCollection();
public BarItemCollection Bars
{
get
{
return bars;
}
set
{
bars = value;
RebuildChart();
}
}
// (Drawing logic omitted.)
}

The last ingredient is the drawing logic for the chart. This logic consists of two parts. The first part steps through the data and determines the maximum BarItem value. All other bar items are sized proportionally.


private int barWidth
decimal maxValue;
public void RebuildChart()
{
// Find out how much space a single bar can occupy.
barWidth = (int)(this.Width / bars.Count);
// Set the maximum value on the chart.
maxValue = 0;
foreach (BarItem bar in bars)
{
if (bar.Value > maxValue)
{
maxValue = bar.Value;
}
}
this.Invalidate();
}

The RebuildChart() method is public, and the client must call it after adding the appropriate BarItem objects. Alternatively, you could add a BarChanged event to the BarItemCollection class, and rebuild the chart in the SimpleChart control whenever this event occurs. However, this approach could hamper performance, because the chart would be recalculated multiple times, as each individual bar is added.

The OnPaint() routine steps through the collection of bars, and draws each one onto the form with the appropriate proportional size. Each bar is created using two rectangles and an outline, for a nice shadowed effect. The BarItem.ShortForm text is also drawn onto each bar.


protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
base.OnPaint(e);
if (bars.Count == 0)
{
return;
}
int x = 0;
int baseLine = this.Height;
Font textFont = new Font("Tahoma", 8);
// Draw each item.
foreach (BarItem bar in bars)
{
int height = (int)(bar.Value / maxValue * this.Height);
int top = this.Height - height;
// Draw bar (two rectangles are used for a shadowed effect),
// along with an outline.
e.Graphics.FillRectangle(Brushes.LightBlue, x + 4, top,
barWidth - 7, height);
e.Graphics.DrawRectangle(new Pen(Color.White, 4), x + 4, top,
barWidth - 4, height);
e.Graphics.FillRectangle(Brushes.SteelBlue, x + 8, top + 4,
barWidth - 9, height - 5);
// Draw title.
e.Graphics.DrawString(bar.ShortForm, textFont, Brushes.White,
x + 15, top + 5);
x += barWidth;
}
// Draw the grid.
e.Graphics.DrawLine(Pens.Black, 0, this.Height - 1, this.Width,
this.Height - 1);
e.Graphics.DrawLine(Pens.Black, 0, 0, 0, this.Height);
}

The code that follows creates a simple chart when the form first loads. The chart is shown in Figure 13-7.


Figure 13-7: A sample chart


private void Form1_Load(object sender, System.EventArgs e)
{
simpleChart1.Bars.Add(new BarItem("1999", 10));
simpleChart1.Bars.Add(new BarItem("2000", 20));
simpleChart1.Bars.Add(new BarItem("2001", 5));
simpleChart1.Bars.Add(new BarItem("2002", 27));
simpleChart1.RebuildChart();
}

This is the same pattern you could follow to create any type of static control. In many ways, it's an easier task than creating a button or a user input control because it doesn't need to support user input or receive the focus, although it may require a significant amount of drawing code. For a faster refresh, you could apply the double-buffering techniques discussed earlier in this chapter.

If you want to start tweaking the SimpleChart control, there are several interesting avenues. You might want to start by developing a better axis, allowing customizable bar captions, or creating a pie chart mode (the Graphics class also exposes a DrawPie() and FillPie() method). Look for SimpleChart project with the online samples for this chapter.


/ 142