65.9K
CodeProject 正在变化。 阅读更多。
Home

InfoBarLite 控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (11投票s)

2002年9月6日

4分钟阅读

viewsIcon

117367

downloadIcon

2232

本文展示了如何使用 C# 创建一个 Windows.Forms 控件。

Sample Image 1 - InfoBarLite1.jpg

Sample Image 2 - InfoBarLite2.jpg

引言

自从微软开始使用一种漂亮的 GUI 风格,在设置窗体顶部显示简要信息以来,我一直想拥有一个自己的。上面显示的截图展示了这样一个控件的示例。我最初用 VB6 创建了这个控件作为 OCX,并在几个项目中使用了它。VB6 版本需要大量使用 Win32 API 函数。然而,为了学习 C# 语法,我决定用这种新语言创建同一个控件,我称之为 InfoBarLite。开始编码后,我发现用 C# 生活要好得多。

该控件具有一些非常好的功能,可以使事情变得更容易

  • 该控件可以同时拥有背景图像和单独的图像。
  • 图像可以通过 9 种不同的方式进行对齐。此外,还可以使用 x 和 y 偏移属性来定位图像。
  • 提供了两个不同的文本属性,每个属性都可以包含多个由 Environment.NewLine 字符分隔的行。
  • 每个文本属性都有自己的 FontForeColorOffsetXOffsetY 属性。
  • 控件的背景色可以是纯色或渐变色。
  • 该控件可以为所有边或每个边提供 9 种不同的边框样式。
  • 它可以作为标题栏或侧边栏使用。

详细说明

正如下面所示,InfoBarLite 控件派生自 System.Windows.Forms.UserControl

public class InfoBarLite : System.Windows.Forms.UserControl
{    // Actual code
    ...
}

控件中最有趣的部分是 OnPaint 事件,因为这通常是所有者绘制控件的情况。首先,绘制背景信息。此信息由 BackStyleBorderSideBoderStyle 属性定义。我想强调的一点是控件的行为。如果 BackStyleGradient,则不绘制背景图像。这意味着 BackStyle 属性优先于 BackgroundImage 属性。相反,如果 BackStyleSolid,则忽略 BackColor 属性。这种行为是设计使然。当然,可以通过修改重写的 OnPaint 事件轻松更改。现在,这是 OnPaint 方法。

   /// <summary>
   /// Overloaded Paint method
   /// </summary>
   /// <param name="pe">PaintEventArgs</param>
   protected override void OnPaint(PaintEventArgs pe)
   {
      // First, repaint the base class
      base.OnPaint(pe);

      Rectangle r = this.ClientRectangle;

      // Draw the background and border(s)
      switch( this.BackStyle )
      {
         case BackStyle.Gradient:  
            LinearGradientBrush gb = new LinearGradientBrush(r, 
                                           this.GradientStartColor, 
                                           this.GradientEndColor,
                                           this.GradientMode);
            if(this.BorderSide == Border3DSide.All)
            {
               ControlPaint.DrawBorder3D(pe.Graphics, r, 
                  this.BorderStyle, this.BorderSide);
                  r.Inflate(-2, -2);
               pe.Graphics.FillRectangle(gb, r);
            }
            else
            {
               pe.Graphics.FillRectangle(gb, r);
               ControlPaint.DrawBorder3D(pe.Graphics, r, 
                     this.BorderStyle, this.BorderSide);
            } 
            gb.Dispose();
            break;

         case BackStyle.Solid:
            if(this.BorderSide == Border3DSide.All) 
            {  
               ControlPaint.DrawBorder3D(pe.Graphics, r, 
                       this.BorderStyle, this.BorderSide);
               r.Inflate(-2, -2);
               SolidBrush sb = new SolidBrush(this.BackColor);
               pe.Graphics.FillRectangle(sb, r); 
               sb.Dispose();
            }
            else
            {
               ControlPaint.DrawBorder3D(pe.Graphics, r, 
                        this.BorderStyle, this.BorderSide);
            }
   
            break;
   
         default:
            ControlPaint.DrawBorder3D(pe.Graphics, r, 
                        this.BorderStyle, this.BorderSide);
            break;
      }

      // Set variables for Image and Text drawing
      StringFormat fmt = new StringFormat();
      fmt.FormatFlags = StringFormatFlags.MeasureTrailingSpaces | 
      StringFormatFlags.DisplayFormatControl |
      StringFormatFlags.FitBlackBox;
      fmt.Trimming = StringTrimming.EllipsisCharacter;

      // Rectangle variables that will be calculated
      RectangleF rImage = new RectangleF(0,0,0,0);
      RectangleF rText1 = new RectangleF(0,0,0,0);
      RectangleF rText2 = new RectangleF(0,0,0,0);

      SizeF sizeText1 = pe.Graphics.MeasureString(this.Text1, 
                      this.Text1Font, ClientRectangle.Size, fmt);
      SizeF sizeText2 = pe.Graphics.MeasureString(this.Text2, 
                      this.Text2Font, ClientRectangle.Size, fmt);

      // Calculate the rectangles before starting to draw
      this.getRects(ref rImage, ref rText1, 
                              sizeText1, ref rText2, sizeText2);

      // Draw the image and the texts
      if(this.Enabled)
      {
         int iImageWidth = 0;
        
         if( this.m_Image != null )
         {
            pe.Graphics.DrawImage(this.m_Image, rImage);
            iImageWidth = this.m_Image.Width;
         } 

         SolidBrush sb = new SolidBrush(this.Text1ForeColor);
         pe.Graphics.DrawString(this.Text1, 
                 this.Text1Font, sb, rText1, fmt);
        
         sb = new SolidBrush(this.Text2ForeColor);
         pe.Graphics.DrawString(this.Text2, this.Text2Font, 
                 sb, rText2, fmt);

         sb.Dispose();
       }
       else
       {
          if( this.m_Image != null )
             ControlPaint.DrawImageDisabled(pe.Graphics, 
                               this.m_Image, (int) rImage.X, (int) rImage.Y, 
                               SystemColors.ControlLight);

          ControlPaint.DrawStringDisabled(pe.Graphics, 
                               this.Text1, this.Text1Font, 
                               SystemColors.ControlLight,
                               rText1, 
                               fmt);

         ControlPaint.DrawStringDisabled(pe.Graphics,
                               this.Text2, this.Text2Font, 
                               SystemColors.ControlLight,
                               rText2,
                               fmt);
      }
   }

用法

使用此控件应该非常简单。只需将其放入窗体,设置所需的属性,即可完成。下面是一个与 Nero 的屏幕非常相似的示例。

Sample Image 2 - InfoBarLite3.jpg

图 3 - 一个示例演示屏幕,显示了该控件作为侧边栏和标题栏。

已知问题/限制

有一些问题需要修复和/或添加。

  • 当控件用作侧边栏时,文本属性不会旋转(垂直)绘制,但这是设计使然。
  • UserControl 类继承的 Font 属性不应向用户显示。目前,我不知道如何做到这一点;因此,任何建议都将受到赞赏。
  • 当在设计模式下的属性窗口中更改 Enabled 属性时,此更改不会反映到控件上。另一方面,如果通过代码更改此属性,控件将按预期运行。再次,我需要有关此问题的建议。
  • 最后一个限制是该控件不支持国际化。在 VS IDE 中,如果将 FormLocalizable 属性设置为 True,IDE 会自动添加代码以检索本地控件(随 VS.NET 一起提供)的正确文本,这些文本将通过资源管理器反映 CurrentCulture。我认为这是本地化应用程序的最简单方法。目前,InfoBarLite 与 IDE 协作不佳,无法完成此任务。如果有人知道如何做到这一点并提供解决方案,我可以更新该控件以使所有人受益。

结论

希望 InfoBarLite 控件能像使我自己的生活一样,使我的同事开发者们的(生活)更轻松。它还将允许您添加一个非常好的用户界面功能,帮助您提高最终用户的体验。如果您查看图 1,此控件将提高我们为用户创建的窗体的可理解性,因为用户现在将获得有关需要他们做什么的更具描述性的信息。传统上,这类信息显示在 StatusBar 控件中。然而,大多数用户并不满意,至少我的用户不满意,因为他们被迫阅读如此小的字体。InfoBarLite 控件试图解决上述可用性问题。它可以显示两种不同风格的文本和一个图像。图像可能比文本更能描述需要完成的任务,因为大多数人倾向于不阅读说明。建议在对话框中使用它,当然,这取决于您。

© . All rights reserved.