UITypeEditor 類別

定義

提供可用來設計值編輯器的基底類別,這些值編輯器可提供使用者介面 (UI),以表示並編輯所支援資料類型的物件值。

public ref class UITypeEditor
public class UITypeEditor
type UITypeEditor = class
Public Class UITypeEditor
繼承
UITypeEditor
衍生

範例

下列程式代碼範例示範 UITypeEditor ,可以使用 來提供設計模式中 屬性視窗 的角度選取介面,與整數、雙精度浮點數或浮點數屬性EditorAttribute產生關聯。 此範例會IWindowsFormsEditorService使用 介面,在設計模式中以 屬性視窗 顯示下拉式控件。 編譯程序代碼,並使用 Visual Studio 的 [工具] 功能表上的 [自定義工具箱] 命令,將元件新增至 [工具箱]。 Create 實例,AngleTestControl然後按兩下屬性視窗中 Angle 屬性旁邊的下拉式按鈕,以使用編輯器設定屬性。

#using <System.Windows.Forms.dll>
#using <System.Drawing.dll>
#using <System.dll>

using namespace System;
using namespace System::ComponentModel;
using namespace System::Drawing;
using namespace System::Drawing::Design;
using namespace System::Windows::Forms;
using namespace System::Windows::Forms::Design;

namespace AngleEditor
{
   // Provides a user interface for adjusting an angle value.
   ref class AngleControl: public System::Windows::Forms::UserControl
   {
   public:

      // Stores the angle.
      double angle;

   private:

      // Stores the rotation offset.
      int rotation;

      // Control state tracking variables.
      int dbx;
      int dby;
      int overButton;

   public:
      AngleControl( double initial_angle )
      {
         this->angle = initial_angle;
         this->SetStyle( static_cast<ControlStyles>(ControlStyles::AllPaintingInWmPaint), true );
         rotation = 0;
         dbx = -10;
         dby = -10;
         overButton = -1;
      }

   protected:
      virtual void OnPaint( System::Windows::Forms::PaintEventArgs^ e ) override
      {
         // Set angle origin point at center of control.
         int originX = (this->Width / 2);
         int originY = (this->Height / 2);

         // Fill background and ellipse and center point.
         e->Graphics->FillRectangle( gcnew SolidBrush( Color::DarkBlue ), 0, 0, this->Width, this->Height );
         e->Graphics->FillEllipse( gcnew SolidBrush( Color::White ), 1, 1, this->Width - 3, this->Height - 3 );
         e->Graphics->FillEllipse( gcnew SolidBrush( Color::SlateGray ), originX - 1, originY - 1, 3, 3 );

         // Draw angle markers.
         int startangle = (270 - rotation) % 360;
         e->Graphics->DrawString( startangle.ToString(), gcnew System::Drawing::Font( "Arial",8.0 ), gcnew SolidBrush( Color::DarkGray ), (float)(this->Width / 2) - 10, (float)10 );
         startangle = (startangle + 90) % 360;
         e->Graphics->DrawString( startangle.ToString(), gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::DarkGray ), (float)this->Width - 18, (float)(this->Height / 2) - 6 );
         startangle = (startangle + 90) % 360;
         e->Graphics->DrawString( startangle.ToString(), gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::DarkGray ), ((float)this->Width / 2) - 6, (float)this->Height - 18 );
         startangle = (startangle + 90) % 360;
         e->Graphics->DrawString( startangle.ToString(), gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::DarkGray ), (float)10, (float)(this->Height / 2) - 6 );

         // Draw line along the current angle.
         double radians = ((((int)(angle + rotation) + 360) % 360) * Math::PI) / (double)180;
         e->Graphics->DrawLine( gcnew Pen( gcnew SolidBrush( Color::Red ),1 ), originX, originY, originX + (int)((double)originX * (double)Math::Cos( radians )), originY + (int)((double)originY * (double)Math::Sin( radians )) );

         // Output angle information.
         e->Graphics->FillRectangle( gcnew SolidBrush( Color::Gray ), this->Width - 84, 3, 82, 13 );
         e->Graphics->DrawString( String::Format( "Angle: {0}", angle.ToString( "F4" ) ), gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::Yellow ), (float)this->Width - 84, (float)2 );

         // Draw square at mouse position of last angle adjustment.
         e->Graphics->DrawRectangle( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), dbx - 2, dby - 2, 4, 4 );

         // Draw rotation adjustment buttons.
         if ( overButton == 1 )
         {
            e->Graphics->FillRectangle( gcnew SolidBrush( Color::Green ), this->Width - 28, this->Height - 14, 12, 12 );
            e->Graphics->FillRectangle( gcnew SolidBrush( Color::Gray ), 2, this->Height - 13, 110, 12 );
            e->Graphics->DrawString( "Rotate 90 degrees left", gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::White ), (float)2, (float)this->Height - 14 );
         }
         else
                  e->Graphics->FillRectangle( gcnew SolidBrush( Color::DarkGreen ), this->Width - 28, this->Height - 14, 12, 12 );

         if ( overButton == 2 )
         {
            e->Graphics->FillRectangle( gcnew SolidBrush( Color::Green ), this->Width - 14, this->Height - 14, 12, 12 );
            e->Graphics->FillRectangle( gcnew SolidBrush( Color::Gray ), 2, this->Height - 13, 116, 12 );
            e->Graphics->DrawString( "Rotate 90 degrees right", gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::White ), (float)2, (float)this->Height - 14 );
         }
         else
                  e->Graphics->FillRectangle( gcnew SolidBrush( Color::DarkGreen ), this->Width - 14, this->Height - 14, 12, 12 );

         e->Graphics->DrawEllipse( gcnew Pen( gcnew SolidBrush( Color::White ),1 ), this->Width - 11, this->Height - 11, 6, 6 );
         e->Graphics->DrawEllipse( gcnew Pen( gcnew SolidBrush( Color::White ),1 ), this->Width - 25, this->Height - 11, 6, 6 );
         if ( overButton == 1 )
                  e->Graphics->FillRectangle( gcnew SolidBrush( Color::Green ), this->Width - 25, this->Height - 6, 4, 4 );
         else
                  e->Graphics->FillRectangle( gcnew SolidBrush( Color::DarkGreen ), this->Width - 25, this->Height - 6, 4, 4 );

         if ( overButton == 2 )
                  e->Graphics->FillRectangle( gcnew SolidBrush( Color::Green ), this->Width - 8, this->Height - 6, 4, 4 );
         else
                  e->Graphics->FillRectangle( gcnew SolidBrush( Color::DarkGreen ), this->Width - 8, this->Height - 6, 4, 4 );

         array<Point>^ temp0 = {Point(this->Width - 7,this->Height - 8),Point(this->Width - 3,this->Height - 8),Point(this->Width - 5,this->Height - 4)};
         e->Graphics->FillPolygon( gcnew SolidBrush( Color::White ), temp0 );
         array<Point>^ temp1 = {Point(this->Width - 26,this->Height - 8),Point(this->Width - 21,this->Height - 8),Point(this->Width - 25,this->Height - 4)};
         e->Graphics->FillPolygon( gcnew SolidBrush( Color::White ), temp1 );
      }

      virtual void OnMouseDown( System::Windows::Forms::MouseEventArgs^ e ) override
      {
         // Handle rotation adjustment button clicks.
         if ( e->X >= this->Width - 28 && e->X <= this->Width - 2 && e->Y >= this->Height - 14 && e->Y <= this->Height - 2 )
         {
            if ( e->X <= this->Width - 16 )
                        rotation -= 90;
            else
            if ( e->X >= this->Width - 14 )
                        rotation += 90;

            if ( rotation < 0 )
                        rotation += 360;

            rotation = rotation % 360;
            dbx = -10;
            dby = -10;
         }
         else
                  UpdateAngle( e->X, e->Y );

         this->Refresh();
      }

      virtual void OnMouseMove( System::Windows::Forms::MouseEventArgs^ e ) override
      {
         if ( e->Button == ::MouseButtons::Left )
         {
            UpdateAngle( e->X, e->Y );
            overButton = -1;
         }
         else
         if ( e->X >= this->Width - 28 && e->X <= this->Width - 16 && e->Y >= this->Height - 14 && e->Y <= this->Height - 2 )
                  overButton = 1;
         else
         if ( e->X >= this->Width - 14 && e->X <= this->Width - 2 && e->Y >= this->Height - 14 && e->Y <= this->Height - 2 )
                  overButton = 2;
         else
                  overButton = -1;

         this->Refresh();
      }

   private:
      void UpdateAngle( int mx, int my )
      {
         // Store mouse coordinates.
         dbx = mx;
         dby = my;
         
         // Translate y coordinate input to GetAngle function to correct for ellipsoid distortion.
         double widthToHeightRatio = (double)this->Width / (double)this->Height;
         int tmy;
         if ( my == 0 )
                  tmy = my;
         else
         if ( my < this->Height / 2 )
                  tmy = (this->Height / 2) - (int)(((this->Height / 2) - my) * widthToHeightRatio);
         else
                  tmy = (this->Height / 2) + (int)((double)(my - (this->Height / 2)) * widthToHeightRatio);

         // Retrieve updated angle based on rise over run.
         angle = (int)(GetAngle( this->Width / 2, this->Height / 2, mx, tmy ) - rotation) % 360;
      }

      double GetAngle( int x1, int y1, int x2, int y2 )
      {
         double degrees;

         // Avoid divide by zero run values.
         if ( x2 - x1 == 0 )
         {
            if ( y2 > y1 )
                        degrees = 90;
            else
                        degrees = 270;
         }
         else
         {
            // Calculate angle from offset.
            double riseoverrun = (double)(y2 - y1) / (double)(x2 - x1);
            double radians = Math::Atan( riseoverrun );
            degrees = radians * ((double)180 / Math::PI);
            
            // Handle quadrant specific transformations.
            if ( (x2 - x1) < 0 || (y2 - y1) < 0 )
                        degrees += 180;

            if ( (x2 - x1) > 0 && (y2 - y1) < 0 )
                        degrees -= 180;

            if ( degrees < 0 )
                        degrees += 360;
         }

         return degrees;
      }
   };

   // This UITypeEditor can be associated with Int32, Double and Single
   // properties to provide a design-mode angle selection interface.
   [System::Security::Permissions::PermissionSetAttribute
   (System::Security::Permissions::SecurityAction::InheritanceDemand, Name="FullTrust")]
   [System::Security::Permissions::PermissionSetAttribute
   (System::Security::Permissions::SecurityAction::LinkDemand, Name="FullTrust")]
   public ref class AngleEditor: public System::Drawing::Design::UITypeEditor
   {
   public:
      AngleEditor(){}

      // Indicates whether the UITypeEditor provides a form-based (modal) dialog,
      // drop down dialog, or no UI outside of the properties window.
      virtual System::Drawing::Design::UITypeEditorEditStyle GetEditStyle( System::ComponentModel::ITypeDescriptorContext^ context ) override
      {
         return UITypeEditorEditStyle::DropDown;
      }

      // Displays the UI for value selection.
      virtual Object^ EditValue( System::ComponentModel::ITypeDescriptorContext^ context, System::IServiceProvider^ provider, Object^ value ) override
      {
         // Return the value if the value is not of type Int32, Double and Single.
         if ( value->GetType() != double::typeid && value->GetType() != float::typeid && value->GetType() != int::typeid )
                  return value;
         
         // Uses the IWindowsFormsEditorService* to display a
         // drop-down UI in the Properties window.
         IWindowsFormsEditorService^ edSvc = dynamic_cast<IWindowsFormsEditorService^>(provider->GetService( IWindowsFormsEditorService::typeid ));
         if ( edSvc != nullptr )
         {
            // Display an angle selection control and retrieve the value.
            AngleControl^ angleControl = gcnew AngleControl(  *dynamic_cast<double^>(value) );
            edSvc->DropDownControl( angleControl );

            // Return the value in the appropraite data format.
            if ( value->GetType() == double::typeid )
                        return angleControl->angle;
            else
            if ( value->GetType() == float::typeid )
                        return (float)angleControl->angle;
            else
            if ( value->GetType() == int::typeid )
                        return (int)angleControl->angle;
         }

         return value;
      }

      // Draws a representation of the property's value.
   private:
      void PaintValue( System::Drawing::Design::PaintValueEventArgs^ e ) new
      {
         int normalX = (e->Bounds.Width / 2);
         int normalY = (e->Bounds.Height / 2);
         
         // Fill background and ellipse and center point.
         e->Graphics->FillRectangle( gcnew SolidBrush( Color::DarkBlue ), e->Bounds.X, e->Bounds.Y, e->Bounds.Width, e->Bounds.Height );
         e->Graphics->FillEllipse( gcnew SolidBrush( Color::White ), e->Bounds.X + 1, e->Bounds.Y + 1, e->Bounds.Width - 3, e->Bounds.Height - 3 );
         e->Graphics->FillEllipse( gcnew SolidBrush( Color::SlateGray ), normalX + e->Bounds.X - 1, normalY + e->Bounds.Y - 1, 3, 3 );
         
         // Draw line along the current angle.
         double radians = ( *dynamic_cast<double^>(e->Value) * Math::PI) / (double)180;
         e->Graphics->DrawLine( gcnew Pen( gcnew SolidBrush( Color::Red ),1 ), normalX + e->Bounds.X, normalY + e->Bounds.Y, e->Bounds.X + (normalX + (int)((double)normalX * Math::Cos( radians ))), e->Bounds.Y + (normalY + (int)((double)normalY * Math::Sin( radians ))) );
      }

      // Indicates whether the UITypeEditor supports painting a
      // representation of a property's value.
      bool GetPaintValueSupported( System::ComponentModel::ITypeDescriptorContext^ context ) new
      {
         return true;
      }
   };

   public ref class AngleEditorTestControl: public System::Windows::Forms::UserControl
   {
   private:
      double int_angle;

   public:

      property double Angle 
      {
         [BrowsableAttribute(true)]
         [EditorAttribute(AngleEditor::typeid,System::Drawing::Design::UITypeEditor::typeid)]
         double get()
         {
            return int_angle;
         }

         void set( double value )
         {
            int_angle = value;
         }

      }
      AngleEditorTestControl()
      {
         int_angle = 90;
         this->Size = System::Drawing::Size( 190, 42 );
         this->BackColor = Color::Beige;
      }

   protected:
      virtual void OnPaint( System::Windows::Forms::PaintEventArgs^ e ) override
      {
         if ( this->DesignMode )
         {
            e->Graphics->DrawString( "Use the Properties Window to access", 
               gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::Black ), 3, 2 );
            e->Graphics->DrawString( "the AngleEditor UITypeEditor by", 
               gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::Black ), 3, 14 );
            e->Graphics->DrawString( "configuring the \"Angle\" property.", 
               gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::Black ), 3, 26 );
         }
         else
            e->Graphics->DrawString( "This example requires design mode.", 
               gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::Black ), 3, 2 );
      }
   };
}
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace AngleEditor
{
    // This UITypeEditor can be associated with Int32, Double and Single
    // properties to provide a design-mode angle selection interface.
    public class AngleEditor : System.Drawing.Design.UITypeEditor
    {
        public AngleEditor()
        {
        }

        // Indicates whether the UITypeEditor provides a form-based (modal) dialog,
        // drop down dialog, or no UI outside of the properties window.
        public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
        {
            return UITypeEditorEditStyle.DropDown;
        }

        // Displays the UI for value selection.
        public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value)
        {
            // Return the value if the value is not of type Int32, Double and Single.
            if( value.GetType() != typeof(double) && value.GetType() != typeof(float) && value.GetType() != typeof(int) )
                return value;

            // Uses the IWindowsFormsEditorService to display a
            // drop-down UI in the Properties window.
            IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
            if( edSvc != null )
            {
                // Display an angle selection control and retrieve the value.
                AngleControl angleControl = new AngleControl((double)value);
                edSvc.DropDownControl( angleControl );

                // Return the value in the appropraite data format.
                if( value.GetType() == typeof(double) )
                    return angleControl.angle;
                else if( value.GetType() == typeof(float) )
                    return (float)angleControl.angle;
                else if( value.GetType() == typeof(int) )
                    return (int)angleControl.angle;
            }
            return value;
        }

        // Draws a representation of the property's value.
        public override void PaintValue(System.Drawing.Design.PaintValueEventArgs e)
        {
            int normalX = (e.Bounds.Width/2);
            int normalY = (e.Bounds.Height/2);

            // Fill background and ellipse and center point.
            e.Graphics.FillRectangle(new SolidBrush(Color.DarkBlue), e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height);
            e.Graphics.FillEllipse(new SolidBrush(Color.White), e.Bounds.X+1, e.Bounds.Y+1, e.Bounds.Width-3, e.Bounds.Height-3);
            e.Graphics.FillEllipse(new SolidBrush(Color.SlateGray), normalX+e.Bounds.X-1, normalY+e.Bounds.Y-1, 3, 3);

            // Draw line along the current angle.
            double radians = ((double)e.Value*Math.PI) / (double)180;
            e.Graphics.DrawLine( new Pen(new SolidBrush(Color.Red), 1), normalX+e.Bounds.X, normalY+e.Bounds.Y,
                e.Bounds.X+ ( normalX + (int)( (double)normalX * Math.Cos( radians ) ) ),
                e.Bounds.Y+ ( normalY + (int)( (double)normalY * Math.Sin( radians ) ) ) );
        }

        // Indicates whether the UITypeEditor supports painting a
        // representation of a property's value.
        public override bool GetPaintValueSupported(System.ComponentModel.ITypeDescriptorContext context)
        {
            return true;
        }
    }

    // Provides a user interface for adjusting an angle value.
    internal class AngleControl : System.Windows.Forms.UserControl
    {
        // Stores the angle.
        public double angle;
        // Stores the rotation offset.
        private int rotation = 0;
        // Control state tracking variables.
        private int dbx = -10;
        private int dby = -10;
        private int overButton = -1;

        public AngleControl(double initial_angle)
        {
            this.angle = initial_angle;
            this.SetStyle( ControlStyles.AllPaintingInWmPaint, true );
        }

        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            // Set angle origin point at center of control.
            int originX = (this.Width/2);
            int originY = (this.Height/2);

            // Fill background and ellipse and center point.
            e.Graphics.FillRectangle(new SolidBrush(Color.DarkBlue), 0, 0, this.Width, this.Height);
            e.Graphics.FillEllipse(new SolidBrush(Color.White), 1, 1, this.Width-3, this.Height-3);
            e.Graphics.FillEllipse(new SolidBrush(Color.SlateGray), originX-1, originY-1, 3, 3);

            // Draw angle markers.
            int startangle = (270-rotation)%360;
            e.Graphics.DrawString(startangle.ToString(), new Font("Arial", 8), new SolidBrush(Color.DarkGray), (this.Width/2)-10, 10);
            startangle = (startangle+90)%360;
            e.Graphics.DrawString(startangle.ToString(), new Font("Arial", 8), new SolidBrush(Color.DarkGray), this.Width-18, (this.Height/2)-6);
            startangle = (startangle+90)%360;
            e.Graphics.DrawString(startangle.ToString(), new Font("Arial", 8), new SolidBrush(Color.DarkGray), (this.Width/2)-6, this.Height-18);
            startangle = (startangle+90)%360;
            e.Graphics.DrawString(startangle.ToString(), new Font("Arial", 8), new SolidBrush(Color.DarkGray), 10, (this.Height/2)-6);

            // Draw line along the current angle.
            double radians = ((((angle+rotation)+360)%360)*Math.PI) / (double)180;
            e.Graphics.DrawLine( new Pen(new SolidBrush(Color.Red), 1), originX, originY,
                originX + (int)( (double)originX * (double)Math.Cos( radians )   ),
                originY + (int)( (double)originY * (double)Math.Sin( radians ) ) );

            // Output angle information.
            e.Graphics.FillRectangle(new SolidBrush(Color.Gray), this.Width-84, 3, 82, 13);
            e.Graphics.DrawString("Angle: "+angle.ToString("F4"), new Font("Arial", 8), new SolidBrush(Color.Yellow), this.Width-84, 2);
            // Draw square at mouse position of last angle adjustment.
            e.Graphics.DrawRectangle(new Pen(new SolidBrush(Color.Black), 1), dbx-2, dby-2, 4, 4);
            // Draw rotation adjustment buttons.
            if( overButton == 1 )
            {
                e.Graphics.FillRectangle(new SolidBrush(Color.Green), this.Width-28, this.Height-14, 12, 12);
                e.Graphics.FillRectangle(new SolidBrush(Color.Gray), 2, this.Height-13, 110, 12);
                e.Graphics.DrawString("Rotate 90 degrees left", new Font("Arial", 8), new SolidBrush(Color.White), 2, this.Height-14);
            }
            else
            {
                e.Graphics.FillRectangle(new SolidBrush(Color.DarkGreen), this.Width-28, this.Height-14, 12, 12);
            }

            if ( overButton == 2 )
            {
                e.Graphics.FillRectangle(new SolidBrush(Color.Green), this.Width-14, this.Height-14, 12, 12);
                e.Graphics.FillRectangle(new SolidBrush(Color.Gray), 2, this.Height-13, 116, 12);
                e.Graphics.DrawString("Rotate 90 degrees right", new Font("Arial", 8), new SolidBrush(Color.White), 2, this.Height-14);
            }
            else
            {
                e.Graphics.FillRectangle(new SolidBrush(Color.DarkGreen), this.Width-14, this.Height-14, 12, 12);
            }

            e.Graphics.DrawEllipse(new Pen(new SolidBrush(Color.White), 1), this.Width-11, this.Height-11, 6, 6);
            e.Graphics.DrawEllipse(new Pen(new SolidBrush(Color.White), 1), this.Width-25, this.Height-11, 6, 6);
            if( overButton == 1 )
                e.Graphics.FillRectangle(new SolidBrush(Color.Green), this.Width-25, this.Height-6, 4, 4);
            else
                e.Graphics.FillRectangle(new SolidBrush(Color.DarkGreen), this.Width-25, this.Height-6, 4, 4);
            if( overButton == 2 )
                e.Graphics.FillRectangle(new SolidBrush(Color.Green), this.Width-8, this.Height-6, 4, 4);
            else
                e.Graphics.FillRectangle(new SolidBrush(Color.DarkGreen), this.Width-8, this.Height-6, 4, 4);
            e.Graphics.FillPolygon(new SolidBrush(Color.White), new Point[] { new Point(this.Width-7, this.Height-8), new Point(this.Width-3, this.Height-8), new Point(this.Width-5, this.Height-4) });
            e.Graphics.FillPolygon(new SolidBrush(Color.White), new Point[] { new Point(this.Width-26, this.Height-8), new Point(this.Width-21, this.Height-8), new Point(this.Width-25, this.Height-4) });
        }

        protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
        {
            // Handle rotation adjustment button clicks.
            if( e.X >= this.Width-28 && e.X <= this.Width-2 && e.Y >= this.Height-14 && e.Y <= this.Height-2 )
            {
                if( e.X <= this.Width-16 )
                    rotation -= 90;
                else if( e.X >= this.Width-14 )
                    rotation += 90;
                if( rotation < 0 )
                    rotation += 360;
                rotation = rotation%360;
                dbx=-10;
                dby=-10;
            }
            else
            {
                UpdateAngle(e.X, e.Y);
            }

            this.Refresh();
        }

        protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
        {
            if( e.Button == MouseButtons.Left )
            {
                UpdateAngle(e.X, e.Y);
                overButton = -1;
            }
            else if( e.X >= this.Width-28 && e.X <= this.Width-16 && e.Y >= this.Height-14 && e.Y <= this.Height-2 )
            {
                overButton = 1;
            }
            else if( e.X >= this.Width-14 && e.X <= this.Width-2 && e.Y >= this.Height-14 && e.Y <= this.Height-2 )
            {
                overButton = 2;
            }
            else
            {
                overButton = -1;
            }

            this.Refresh();
        }

        private void UpdateAngle(int mx, int my)
        {
            // Store mouse coordinates.
            dbx = mx;
            dby = my;

            // Translate y coordinate input to GetAngle function to correct for ellipsoid distortion.
            double widthToHeightRatio =  (double)this.Width/(double)this.Height;
            int tmy;
            if( my == 0 )
                tmy = my;
            else if( my < this.Height/2 )
                tmy = (this.Height/2)-(int)(((this.Height/2)-my)*widthToHeightRatio);
            else
                tmy = (this.Height/2)+(int)((double)(my-(this.Height/2))*widthToHeightRatio);

            // Retrieve updated angle based on rise over run.
            angle = (GetAngle(this.Width/2, this.Height/2, mx, tmy)-rotation)%360;
        }

        private double GetAngle(int x1, int y1, int x2, int y2)
        {
            double degrees;

            // Avoid divide by zero run values.
            if( x2-x1 == 0 )
            {
                if( y2 > y1 )
                    degrees = 90;
                else
                    degrees = 270;
            }
            else
            {
                // Calculate angle from offset.
                double riseoverrun = (double)(y2-y1)/(double)(x2-x1);
                double radians = Math.Atan( riseoverrun );
                degrees = radians * ((double)180/Math.PI);

                // Handle quadrant specific transformations.
                if( (x2-x1) < 0 || (y2-y1) < 0 )
                    degrees += 180;
                if( (x2-x1) > 0 && (y2-y1) < 0 )
                    degrees -= 180;
                if( degrees < 0 )
                    degrees += 360;
            }
            return degrees;
        }
    }

    public class AngleEditorTestControl : System.Windows.Forms.UserControl
    {
        private double int_angle;

        [BrowsableAttribute(true)]
        [EditorAttribute(typeof(AngleEditor), typeof(System.Drawing.Design.UITypeEditor))]
        public double Angle
        {
            get
            { return int_angle; }
            set
            { int_angle = value; }
        }

        public AngleEditorTestControl()
        {
            int_angle = 90;
            this.Size = new Size(190, 42);
            this.BackColor = Color.Beige;			
        }

        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            if( this.DesignMode )
            {
                e.Graphics.DrawString("Use the Properties Window to access", new Font("Arial", 8), new SolidBrush(Color.Black), 3,2);
                e.Graphics.DrawString("the AngleEditor UITypeEditor by", new Font("Arial", 8), new SolidBrush(Color.Black), 3,14);
                e.Graphics.DrawString("configuring the \"Angle\" property.", new Font("Arial", 8), new SolidBrush(Color.Black), 3,26);
            }
            else
            {
                e.Graphics.DrawString("This example requires design mode.", new Font("Arial", 8), new SolidBrush(Color.Black), 3,2);
            }
        }
    }
}
Option Strict Off
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Design
Imports System.Reflection
Imports System.Windows.Forms
Imports System.Windows.Forms.Design

' This UITypeEditor can be associated with Int32, Double and Single
' properties to provide a design-mode angle selection interface.
<System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")> _
Public Class AngleEditor
    Inherits System.Drawing.Design.UITypeEditor

    Public Sub New()
    End Sub

    ' Indicates whether the UITypeEditor provides a form-based (modal) dialog, 
    ' drop down dialog, or no UI outside of the properties window.
    Public Overloads Overrides Function GetEditStyle(ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.Drawing.Design.UITypeEditorEditStyle
        Return UITypeEditorEditStyle.DropDown
    End Function

    ' Displays the UI for value selection.
    Public Overloads Overrides Function EditValue(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal provider As System.IServiceProvider, ByVal value As Object) As Object
        ' Return the value if the value is not of type Int32, Double and Single.
        If value.GetType() IsNot GetType(Double) AndAlso value.GetType() IsNot GetType(Single) AndAlso value.GetType() IsNot GetType(Integer) Then
            Return value
        End If
        ' Uses the IWindowsFormsEditorService to display a 
        ' drop-down UI in the Properties window.
        Dim edSvc As IWindowsFormsEditorService = CType(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)
        If (edSvc IsNot Nothing) Then
            ' Display an angle selection control and retrieve the value.
            Dim angleControl As New AngleControl(System.Convert.ToDouble(value))
            edSvc.DropDownControl(angleControl)

            ' Return the value in the appropraite data format.
            If value Is GetType(Double) Then
                Return angleControl.angle
            ElseIf value Is GetType(Single) Then
                Return System.Convert.ToSingle(angleControl.angle)
            ElseIf value Is GetType(Integer) Then
                Return System.Convert.ToInt32(angleControl.angle)
            End If
        End If
        Return value
    End Function

    ' Draws a representation of the property's value.
    Public Overloads Overrides Sub PaintValue(ByVal e As System.Drawing.Design.PaintValueEventArgs)
        Dim normalX As Integer = e.Bounds.Width / 2
        Dim normalY As Integer = e.Bounds.Height / 2

        ' Fill background and ellipse and center point.
        e.Graphics.FillRectangle(New SolidBrush(Color.DarkBlue), e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height)
        e.Graphics.FillEllipse(New SolidBrush(Color.White), e.Bounds.X + 1, e.Bounds.Y + 1, e.Bounds.Width - 3, e.Bounds.Height - 3)
        e.Graphics.FillEllipse(New SolidBrush(Color.SlateGray), normalX + e.Bounds.X - 1, normalY + e.Bounds.Y - 1, 3, 3)

        ' Draw line along the current angle.
        Dim radians As Double = System.Convert.ToDouble(e.Value) * Math.PI / System.Convert.ToDouble(180)
        e.Graphics.DrawLine(New Pen(New SolidBrush(Color.Red), 1), normalX + e.Bounds.X, normalY + e.Bounds.Y, e.Bounds.X + (normalX + System.Convert.ToInt32(System.Convert.ToDouble(normalX) * Math.Cos(radians))), e.Bounds.Y + (normalY + System.Convert.ToInt32(System.Convert.ToDouble(normalY) * Math.Sin(radians))))
    End Sub

    ' Indicates whether the UITypeEditor supports painting a 
    ' representation of a property's value.
    Public Overloads Overrides Function GetPaintValueSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
        Return True
    End Function
End Class

' Provides a user interface for adjusting an angle value.
Friend Class AngleControl
    Inherits System.Windows.Forms.UserControl

    ' Stores the angle.
    Public angle As Double
    ' Stores the rotation offset.
    Private rotation As Integer = 0
    ' Control state tracking variables.
    Private dbx As Integer = -10
    Private dby As Integer = -10
    Private overButton As Integer = -1

    Public Sub New(ByVal initial_angle As Double)
        Me.angle = initial_angle
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        ' Set angle origin point at center of control.
        Dim originX As Integer = Me.Width / 2
        Dim originY As Integer = Me.Height / 2

        ' Fill background and ellipse and center point.
        e.Graphics.FillRectangle(New SolidBrush(Color.DarkBlue), 0, 0, Me.Width, Me.Height)
        e.Graphics.FillEllipse(New SolidBrush(Color.White), 1, 1, Me.Width - 3, Me.Height - 3)
        e.Graphics.FillEllipse(New SolidBrush(Color.SlateGray), originX - 1, originY - 1, 3, 3)

        ' Draw angle markers.
        Dim startangle As Integer = (270 - rotation) Mod 360
        e.Graphics.DrawString(startangle.ToString(), New Font("Arial", 8), New SolidBrush(Color.DarkGray), Me.Width / 2 - 10, 10)
        startangle = (startangle + 90) Mod 360
        e.Graphics.DrawString(startangle.ToString(), New Font("Arial", 8), New SolidBrush(Color.DarkGray), Me.Width - 18, Me.Height / 2 - 6)
        startangle = (startangle + 90) Mod 360
        e.Graphics.DrawString(startangle.ToString(), New Font("Arial", 8), New SolidBrush(Color.DarkGray), Me.Width / 2 - 6, Me.Height - 18)
        startangle = (startangle + 90) Mod 360
        e.Graphics.DrawString(startangle.ToString(), New Font("Arial", 8), New SolidBrush(Color.DarkGray), 10, Me.Height / 2 - 6)

        ' Draw line along the current angle.   
        Dim radians As Double = ((angle + rotation + 360) Mod 360) * Math.PI / System.Convert.ToDouble(180)
        e.Graphics.DrawLine(New Pen(New SolidBrush(Color.Red), 1), originX, originY, originX + System.Convert.ToInt32(System.Convert.ToDouble(originX) * Math.Cos(radians)), originY + System.Convert.ToInt32(System.Convert.ToDouble(originY) * Math.Sin(radians)))

        ' Output angle information.
        e.Graphics.FillRectangle(New SolidBrush(Color.Gray), Me.Width - 84, 3, 82, 13)
        e.Graphics.DrawString("Angle: " + angle.ToString("F4"), New Font("Arial", 8), New SolidBrush(Color.Yellow), Me.Width - 84, 2)
        ' Draw square at mouse position of last angle adjustment.
        e.Graphics.DrawRectangle(New Pen(New SolidBrush(Color.Black), 1), dbx - 2, dby - 2, 4, 4)
        ' Draw rotation adjustment buttons.
        If overButton = 1 Then
            e.Graphics.FillRectangle(New SolidBrush(Color.Green), Me.Width - 28, Me.Height - 14, 12, 12)
            e.Graphics.FillRectangle(New SolidBrush(Color.Gray), 2, Me.Height - 13, 110, 12)
            e.Graphics.DrawString("Rotate 90 degrees left", New Font("Arial", 8), New SolidBrush(Color.White), 2, Me.Height - 14)
        Else
            e.Graphics.FillRectangle(New SolidBrush(Color.DarkGreen), Me.Width - 28, Me.Height - 14, 12, 12)
        End If
        If overButton = 2 Then
            e.Graphics.FillRectangle(New SolidBrush(Color.Green), Me.Width - 14, Me.Height - 14, 12, 12)
            e.Graphics.FillRectangle(New SolidBrush(Color.Gray), 2, Me.Height - 13, 116, 12)
            e.Graphics.DrawString("Rotate 90 degrees right", New Font("Arial", 8), New SolidBrush(Color.White), 2, Me.Height - 14)
        Else
            e.Graphics.FillRectangle(New SolidBrush(Color.DarkGreen), Me.Width - 14, Me.Height - 14, 12, 12)
        End If
        e.Graphics.DrawEllipse(New Pen(New SolidBrush(Color.White), 1), Me.Width - 11, Me.Height - 11, 6, 6)
        e.Graphics.DrawEllipse(New Pen(New SolidBrush(Color.White), 1), Me.Width - 25, Me.Height - 11, 6, 6)
        If overButton = 1 Then
            e.Graphics.FillRectangle(New SolidBrush(Color.Green), Me.Width - 25, Me.Height - 6, 4, 4)
        Else
            e.Graphics.FillRectangle(New SolidBrush(Color.DarkGreen), Me.Width - 25, Me.Height - 6, 4, 4)
        End If
        If overButton = 2 Then
            e.Graphics.FillRectangle(New SolidBrush(Color.Green), Me.Width - 8, Me.Height - 6, 4, 4)
        Else
            e.Graphics.FillRectangle(New SolidBrush(Color.DarkGreen), Me.Width - 8, Me.Height - 6, 4, 4)
        End If
        e.Graphics.FillPolygon(New SolidBrush(Color.White), New Point() {New Point(Me.Width - 7, Me.Height - 8), New Point(Me.Width - 3, Me.Height - 8), New Point(Me.Width - 5, Me.Height - 4)})
        e.Graphics.FillPolygon(New SolidBrush(Color.White), New Point() {New Point(Me.Width - 26, Me.Height - 8), New Point(Me.Width - 21, Me.Height - 8), New Point(Me.Width - 25, Me.Height - 4)})
    End Sub

    Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
        ' Handle rotation adjustment button clicks.
        If e.X >= Me.Width - 28 AndAlso e.X <= Me.Width - 2 AndAlso e.Y >= Me.Height - 14 AndAlso e.Y <= Me.Height - 2 Then
            If e.X <= Me.Width - 16 Then
                rotation -= 90
            ElseIf e.X >= Me.Width - 14 Then
                rotation += 90
            End If
            If rotation < 0 Then
                rotation += 360
            End If
            rotation = rotation Mod 360
            dbx = -10
            dby = -10
        Else
            UpdateAngle(e.X, e.Y)
        End If
        Me.Refresh()
    End Sub

    Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
        If e.Button = System.Windows.Forms.MouseButtons.Left Then
            UpdateAngle(e.X, e.Y)
            overButton = -1
        ElseIf e.X >= Me.Width - 28 AndAlso e.X <= Me.Width - 16 AndAlso e.Y >= Me.Height - 14 AndAlso e.Y <= Me.Height - 2 Then
            overButton = 1
        ElseIf e.X >= Me.Width - 14 AndAlso e.X <= Me.Width - 2 AndAlso e.Y >= Me.Height - 14 AndAlso e.Y <= Me.Height - 2 Then
            overButton = 2
        Else
            overButton = -1
        End If
        Me.Refresh()
    End Sub

    Private Sub UpdateAngle(ByVal mx As Integer, ByVal my As Integer)
        ' Store mouse coordinates.
        dbx = mx
        dby = my

        ' Translate y coordinate input to GetAngle function to correct for ellipsoid distortion.
        Dim widthToHeightRatio As Double = System.Convert.ToDouble(Me.Width) / System.Convert.ToDouble(Me.Height)
        Dim tmy As Integer
        If my = 0 Then
            tmy = my
        ElseIf my < Me.Height / 2 Then
            tmy = Me.Height / 2 - Fix((Me.Height / 2 - my) * widthToHeightRatio)
        Else
            tmy = Me.Height / 2 + Fix(System.Convert.ToDouble(my - Me.Height / 2) * widthToHeightRatio)
        End If
        ' Retrieve updated angle based on rise over run.
        angle = (GetAngle(Me.Width / 2, Me.Height / 2, mx, tmy) - rotation) Mod 360
    End Sub

    Private Function GetAngle(ByVal x1 As Integer, ByVal y1 As Integer, ByVal x2 As Integer, ByVal y2 As Integer) As Double
        Dim degrees As Double

        ' Avoid divide by zero run values.
        If x2 - x1 = 0 Then
            If y2 > y1 Then
                degrees = 90
            Else
                degrees = 270
            End If
        Else
            ' Calculate angle from offset.
            Dim riseoverrun As Double = System.Convert.ToDouble(y2 - y1) / System.Convert.ToDouble(x2 - x1)
            Dim radians As Double = Math.Atan(riseoverrun)
            degrees = radians * (System.Convert.ToDouble(180) / Math.PI)

            ' Handle quadrant specific transformations.           
            If x2 - x1 < 0 OrElse y2 - y1 < 0 Then
                degrees += 180
            End If
            If x2 - x1 > 0 AndAlso y2 - y1 < 0 Then
                degrees -= 180
            End If
            If degrees < 0 Then
                degrees += 360
            End If
        End If
        Return degrees
    End Function
End Class

Public Class AngleEditorTestControl
    Inherits System.Windows.Forms.UserControl
    Private int_angle As Double

    <BrowsableAttribute(True), EditorAttribute(GetType(AngleEditor), GetType(System.Drawing.Design.UITypeEditor))> _
    Public Property Angle() As Double
        Get
            Return int_angle
        End Get
        Set(ByVal Value As Double)
            int_angle = Value
        End Set
    End Property

    Public Sub New()
        int_angle = 90
        Me.Size = New Size(190, 42)
        Me.BackColor = Color.Beige
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        If Me.DesignMode Then
            e.Graphics.DrawString("Use the Properties Window to access", New Font("Arial", 8), New SolidBrush(Color.Black), 3, 2)
            e.Graphics.DrawString("the AngleEditor UITypeEditor by", New Font("Arial", 8), New SolidBrush(Color.Black), 3, 14)
            e.Graphics.DrawString("configuring the ""Angle"" property.", New Font("Arial", 8), New SolidBrush(Color.Black), 3, 26)
        Else
            e.Graphics.DrawString("This example requires design mode.", New Font("Arial", 8), New SolidBrush(Color.Black), 3, 2)
        End If
    End Sub
End Class

備註

類別 UITypeEditor 提供可衍生自的基類,並加以擴充,以實作設計時間環境的自定義類型編輯器。 一般而言,您的自定義類型編輯器會與 PropertyGrid 控件互動。

當文字框值編輯器不足以有效地選取特定類型的值時,自定義類型編輯器會很有用。

若要實作自訂設計時間 UI 類型編輯器,您必須執行下列步驟:

  • 定義衍生自 UITypeEditor 的類別。

  • EditValue覆寫 方法來處理使用者介面、使用者輸入處理和值指派。

  • GetEditStyle覆寫 方法,以通知 屬性視窗 編輯器將使用的編輯器樣式類型。

您可以執行下列步驟,在 屬性視窗 中新增繪製值表示法的額外支援:

  • GetPaintValueSupported覆寫 方法,指出編輯器支持顯示值的表示法。

  • PaintValue覆寫 方法來實作值表示法的顯示。

  • UITypeEditor如果編輯器應該有初始化行為,請覆寫建構函式方法。

注意

類別 UITypeEditor 不支援由右至左 (RTL) 版面配置。

如需增強設計時間支援的詳細資訊,請參閱 擴充 Design-Time 支援。 如需實作 UITypeEditor的詳細資訊,請參閱 使用者介面類型編輯器概觀

建構函式

UITypeEditor()

初始化 UITypeEditor 類別的新執行個體。

屬性

IsDropDownResizable

取得值,表示使用者是否能夠調整下拉式編輯器的大小。

方法

EditValue(IServiceProvider, Object)

使用由 GetEditStyle() 方法指示的編輯器樣式,來編輯指定物件的值。

EditValue(ITypeDescriptorContext, IServiceProvider, Object)

使用由 GetEditStyle() 方法所表示的編輯器樣式來編輯指定的物件值。

Equals(Object)

判斷指定的物件是否等於目前的物件。

(繼承來源 Object)
GetEditStyle()

取得 EditValue(IServiceProvider, Object) 方法所使用的編輯器樣式。

GetEditStyle(ITypeDescriptorContext)

取得 EditValue(IServiceProvider, Object) 方法所使用的編輯器樣式。

GetHashCode()

做為預設雜湊函式。

(繼承來源 Object)
GetPaintValueSupported()

指出這個編輯器是否支援繪製物件值的表示。

GetPaintValueSupported(ITypeDescriptorContext)

指出指定的內容是否支援在指定的內容中繪製物件值的表示。

GetType()

取得目前執行個體的 Type

(繼承來源 Object)
MemberwiseClone()

建立目前 Object 的淺層複製。

(繼承來源 Object)
PaintValue(Object, Graphics, Rectangle)

將指定物件的表示值繪製到指定的畫布上。

PaintValue(PaintValueEventArgs)

使用指定的 PaintValueEventArgs 來繪製物件值的表示。

ToString()

傳回代表目前物件的字串。

(繼承來源 Object)

適用於

另請參閱