C#为复杂属性提供下拉式编辑框和弹出式编辑框

2024-08-23 13:20

本文主要是介绍C#为复杂属性提供下拉式编辑框和弹出式编辑框,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一.为属性提供编辑类

  弹出式和下拉式是如何实现的呢,这需要为属性提供一个专门的编辑类。.Net为我们提供了一个System.Drawing.Design.UITypeEditor类,它是所有编辑类的基类,从他继承出了诸如ColorEditor、FontEditor的类,因此我们可以在属性框中编辑颜色和字体。定义了这样的类,我们也可以为自己的属性实现弹出式和下拉式编辑方式。

  先看一下MSDN中对UITypeEditor的介绍:提供可用于设计值编辑器的基类,这些编辑器可提供用户界面 (UI),用来表示和编辑所支持的数据类型的对象值。

 UITypeEditor 类提供一种基类,可以从该基类派生和进行扩展,以便为设计时环境实现自定义类型编辑器。通常,您的自定义类型编辑器与 PropertyGrid 控件进行交互。在文本框值编辑器不足以有效地选择某些类型的值的情况下,自定义类型编辑器非常有用。

 

继承者说明:若要实现自定义设计时 UI 类型编辑器,必须执行下列步骤

using System;
using System.Drawing;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;public class MyCustomEditor : UITypeEditor
{// 1. 指定编辑器样式:Modal 表示使用弹出对话框public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)// 2. 处理属性值的编辑public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)// 3. 支持绘制值的表示形式public override bool GetPaintValueSupported(ITypeDescriptorContext context)// 4. 绘制值的表示形式public override void PaintValue(PaintValueEventArgs e)//5 .设置默认值或执行其他初始化逻辑public MyCustomEditor() }

1. 定义一个从 UITypeEditor 派生的类

  • 目的:创建一个新的编辑器类,用于自定义编辑属性值的方式。
  • 步骤:从 UITypeEditor 基类继承,通常会定义一个新类,例如 MyCustomEditor

2. 重写 EditValue 方法

  • 目的:处理用户界面和用户输入操作,以及对属性值的分配。

  • 步骤:在 EditValue 方法中,你将实现弹出对话框或其他用户界面,允许用户输入新值,然后将这个值应用到目标属性上。例如:

    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value){ // 实现自定义编辑逻辑 // 例如,显示对话框让用户输入新值 // 更新并返回新的值}

3. 重写 GetEditStyle 方法

  • 目的:通知“属性”窗口该编辑器使用的编辑器样式。

  • 步骤GetEditStyle 方法返回一个 UITypeEditorEditStyle 枚举值,指示编辑器的类型(如 UITypeEditorEditStyle.ModalUITypeEditorEditStyle.DropDownUITypeEditorEditStyle.None)。例如:

    public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) 
    { return UITypeEditorEditStyle.Modal; // 或其他适当的样式
    }

4. 支持值的表示形式(可选)

  • 目的:在属性窗口中显示值的可视化表示形式。

  • 步骤:实现这部分功能时,你需要:

    • 重写 GetPaintValueSupported 方法:指示编辑器是否支持显示值的表示形式。返回 true 表示支持,false 表示不支持。

      public override bool GetPaintValueSupported(ITypeDescriptorContext context) 
      { return true; // 表示支持绘制值的表示形式 
      }
    • 重写 PaintValue 方法:实现如何绘制值的表示形式。例如,你可以绘制一个图标或图像,代表属性的当前值。

      public override void PaintValue(PaintValueEventArgs e) 
      { 
      // 实现绘制逻辑 
      // 例如绘制一个矩形来显示颜色值 
      e.Graphics.FillRectangle(new SolidBrush(Color.Red),e.Bounds); 
      }

5. 初始化行为(可选)

  • 目的:如果编辑器需要特定的初始化行为,你可以重写 UITypeEditor 的构造函数。

  • 步骤:在自定义构造函数中,你可以设置默认值或执行其他初始化逻辑。

    public MyCustomEditor() 
    { // 实现初始化逻辑 }

这些步骤为你提供了创建和自定义 UITypeEditor 的基础,以便在设计时属性窗口中更好地管理和展示属性值。

 

 接下来我们来实现下拉式编辑方式,接下来举一个具体的例子来说明:

  首先假如我们有一个控件类MyControl:

public class MyControl : System.Windows.Forms.UserControl
{private double _angle;[BrowsableAttribute(true)]public double Angle{get{ return _angle; }set{ _angle = value; }}public MyControl(){this._angle = 90;}protected override void OnPaint(System.Windows.Forms.PaintEventArgs e){e.Graphics.DrawString("The Angle is " + _angle, this.Font, Brushes.Red,0,0);}
}

其中有个属性Angle,我们要为其提供下拉式和弹出式编辑方式,当然了,一般都是较为复杂的属性才需要,这里只是为了举例说明。

二.下拉式编辑方式 

  我们为其定义一个派生的编辑类AngleEditor,EditValue和GetEditStyle两个函数,这是必须要重写的:

[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]public class AngleEditor : System.Drawing.Design.UITypeEditor
{public AngleEditor(){}//下拉式还是弹出式public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context){return UITypeEditorEditStyle.DropDown;}// 为属性显示UI编辑框public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value){//值类型不为double,直接返回valueif (value.GetType() != typeof(double))return value;//值为double,显示下拉式或弹出编辑框IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));if (edSvc != null){// 显示编辑框并初始化编辑框的值AngleControl angleControl = new AngleControl((double)value);edSvc.DropDownControl(angleControl);// 返回编辑框中编辑的值.if (value.GetType() == typeof(double))return angleControl.angle;}return value;}//下面两个函数是为了在PropertyGrid中显示一个辅助的效果//可以不用重写public override void PaintValue(System.Drawing.Design.PaintValueEventArgs e){int normalX = (e.Bounds.Width / 2);int normalY = (e.Bounds.Height / 2);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);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))));}public override bool GetPaintValueSupported(System.ComponentModel.ITypeDescriptorContext context){return true;}}// 这里是我们要显示出来的编辑器,把它作为一个内置类,本质上他就是一个显示form//从UserControl继承,要在上面EditValue函数中使用的internal class AngleControl : System.Windows.Forms.UserControl{public double angle; //编辑的角度private float x;     //鼠标位置private float y;public AngleControl(double initial_angle){this.angle = initial_angle;}//显现时,显示属性的当前值protected override void OnLoad(EventArgs e){int originX = (this.Width / 2);int originY = (this.Height / 2);this.x = (float)(50 * Math.Cos(this.angle * Math.PI / 180) + originX);this.y = (float)(50 * Math.Sin(this.angle * Math.PI / 180) + originY);base.OnLoad(e);}//绘制控件,用来显示编辑角度protected override void OnPaint(System.Windows.Forms.PaintEventArgs e){int originX = (this.Width / 2);int originY = (this.Height / 2);e.Graphics.DrawEllipse(Pens.Black, originX - 50, originY - 50, 100, 100);e.Graphics.DrawLine(Pens.Black, originX, originY, x, y);e.Graphics.DrawString("Angle:" + this.angle, this.Font, Brushes.Red, 0, 0);}//鼠标移动时设置角度protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e){if (e.Button == MouseButtons.Left){int originX = (this.Width / 2);int originY = (this.Height / 2);double len = Math.Sqrt(Math.Pow(e.X - originX, 2) + Math.Pow(e.Y - originY, 2));double h = e.Y - originY;this.angle = Math.Asin(h / len);if ((e.X >= originX && e.Y >= originY)){this.x = (float)(50 * Math.Cos(this.angle) + originX);this.y = (float)(50 * Math.Sin(this.angle) + originY);this.angle = this.angle * 180 / Math.PI;}else if (e.X < originX && e.Y > originY){this.x = (float)(originX - 50 * Math.Cos(this.angle));this.y = (float)(50 * Math.Sin(this.angle) + originY);this.angle = 180 - this.angle * 180 / Math.PI;}else if (e.X < originX && e.Y < originY){this.x = (float)(originX - 50 * Math.Cos(this.angle));this.y = (float)(originY + 50 * Math.Sin(this.angle));this.angle = 180 - this.angle * 180 / Math.PI;}else if (e.X >= originX && e.Y <= originY){this.x = (float)(originX + 50 * Math.Cos(this.angle));this.y = (float)(originY + 50 * Math.Sin(this.angle));this.angle = 360 + this.angle * 180 / Math.PI;}this.Invalidate();}          }      
}

这里有两个类,一个是AngleEditor,他就是我们要用于到属性特性中的编辑类,一个是AngleControl,他是辅助AngleEditor来编辑属性的,也就是说,他就是一个form,当我们编辑属性时,他会显现出来,供我们编辑属性值,可以是textBox,图形,表格,各种方式,只需要最后他返回编辑好的属性值给AngleEditor类。在AngleEditor类中的EditValue函数中,我们会调用AngleControl类,并接受它返回的值。

  设计好编辑类后,把它应用到MyControl类中的Angle属性中,在Angle属性中增加特性[EditorAttribute(typeof(AngleEditor), typeof(System.Drawing.Design.UITypeEditor))],相当于告诉PropertyGrid我们要用AngleEditor来编辑这个属性。  

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

效果如下:

三.弹出式编辑方式

  实现了下拉式,我们来实现弹出式,弹出式和下拉式非常的相像,现在要弹出一个编辑框,因此我们的AngleControl类不能从UserControl继承,而从From继承,让他成为一个对话框,在AngleEditor的EditValue函数中,弹出他并接受返回值,如下:

[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]public class AngleEditor : System.Drawing.Design.UITypeEditor
{public AngleEditor(){}//下拉式还是弹出式.//这里是第一个修改的地方,改为了弹出式。public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context){return UITypeEditorEditStyle.Modal;//弹出式}// 为属性显示UI编辑框public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value){//值类型不为double,直接返回valueif (value.GetType() != typeof(double))return value;//值为double,显示下拉式或弹出编辑框IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));if (edSvc != null){// 显示编辑框并初始化编辑框的值,//这里是第二个修改点,改为showDialogAngleControl2 angleControl = new AngleControl2((double)value);edSvc.ShowDialog(angleControl);                // 返回编辑框中编辑的值.if (value.GetType() == typeof(double))return angleControl.angle;}return value;}//下面两个函数是为了在PropertyGrid中显示一个辅助的效果//可以不用重写public override void PaintValue(System.Drawing.Design.PaintValueEventArgs e){int normalX = (e.Bounds.Width / 2);int normalY = (e.Bounds.Height / 2);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);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))));}public override bool GetPaintValueSupported(System.ComponentModel.ITypeDescriptorContext context){return true;}}// 这里是我们要显示出来的编辑器,把它作为一个内置类//从UserControl继承,要在上面EditValue函数中使用的//这里是第三个修改点,让他显示为对话框,所以继承了form类internal class AngleControl2 : System.Windows.Forms.Form{public double angle; //编辑的角度private float x;     //鼠标位置private float y;public AngleControl(double initial_angle){this.angle = initial_angle;}//显现时,显示属性的当前值protected override void OnLoad(EventArgs e){int originX = (this.Width / 2);int originY = (this.Height / 2);this.x = (float)(50 * Math.Cos(this.angle * Math.PI / 180) + originX);this.y = (float)(50 * Math.Sin(this.angle * Math.PI / 180) + originY);base.OnLoad(e);}//绘制控件,用来显示编辑角度protected override void OnPaint(System.Windows.Forms.PaintEventArgs e){int originX = (this.Width / 2);int originY = (this.Height / 2);e.Graphics.DrawEllipse(Pens.Black, originX - 50, originY - 50, 100, 100);e.Graphics.DrawLine(Pens.Black, originX, originY, x, y);e.Graphics.DrawString("Angle:" + this.angle, this.Font, Brushes.Red, 0, 0);}//鼠标移动时设置角度protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e){if (e.Button == MouseButtons.Left){int originX = (this.Width / 2);int originY = (this.Height / 2);double len = Math.Sqrt(Math.Pow(e.X - originX, 2) + Math.Pow(e.Y - originY, 2));double h = e.Y - originY;this.angle = Math.Asin(h / len);if ((e.X >= originX && e.Y >= originY)){this.x = (float)(50 * Math.Cos(this.angle) + originX);this.y = (float)(50 * Math.Sin(this.angle) + originY);this.angle = this.angle * 180 / Math.PI;}else if (e.X < originX && e.Y > originY){this.x = (float)(originX - 50 * Math.Cos(this.angle));this.y = (float)(50 * Math.Sin(this.angle) + originY);this.angle = 180 - this.angle * 180 / Math.PI;}else if (e.X < originX && e.Y < originY){this.x = (float)(originX - 50 * Math.Cos(this.angle));this.y = (float)(originY + 50 * Math.Sin(this.angle));this.angle = 180 - this.angle * 180 / Math.PI;}else if (e.X >= originX && e.Y <= originY){this.x = (float)(originX + 50 * Math.Cos(this.angle));this.y = (float)(originY + 50 * Math.Sin(this.angle));this.angle = 360 + this.angle * 180 / Math.PI;}this.Invalidate();}}}

 

可以看到,只修改了三个地方:

1.AngleEditor类中GetEditStyle函数返回Modal,表明是以弹出式编辑。

2.AngleEditor类中EditValue函数中调用编辑控件的方式:

      AngleControl2 angleControl = new AngleControl2((double)value);
      edSvc.ShowDialog(angleControl);    

3.AngleControl2从Form继承,让他显示为对话框,这里为了区别上面的AngleControl类,将其改成了AngleControl2。

效果如下:

这篇关于C#为复杂属性提供下拉式编辑框和弹出式编辑框的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1099500

相关文章

一文解析C#中的StringSplitOptions枚举

《一文解析C#中的StringSplitOptions枚举》StringSplitOptions是C#中的一个枚举类型,用于控制string.Split()方法分割字符串时的行为,核心作用是处理分割后... 目录C#的StringSplitOptions枚举1.StringSplitOptions枚举的常用

vue监听属性watch的用法及使用场景详解

《vue监听属性watch的用法及使用场景详解》watch是vue中常用的监听器,它主要用于侦听数据的变化,在数据发生变化的时候执行一些操作,:本文主要介绍vue监听属性watch的用法及使用场景... 目录1. 监听属性 watch2. 常规用法3. 监听对象和route变化4. 使用场景附Watch 的

C#自动化实现检测并删除PDF文件中的空白页面

《C#自动化实现检测并删除PDF文件中的空白页面》PDF文档在日常工作和生活中扮演着重要的角色,本文将深入探讨如何使用C#编程语言,结合强大的PDF处理库,自动化地检测并删除PDF文件中的空白页面,感... 目录理解PDF空白页的定义与挑战引入Spire.PDF for .NET库核心实现:检测并删除空白页

C#利用Free Spire.XLS for .NET复制Excel工作表

《C#利用FreeSpire.XLSfor.NET复制Excel工作表》在日常的.NET开发中,我们经常需要操作Excel文件,本文将详细介绍C#如何使用FreeSpire.XLSfor.NET... 目录1. 环境准备2. 核心功能3. android示例代码3.1 在同一工作簿内复制工作表3.2 在不同

C#中通过Response.Headers设置自定义参数的代码示例

《C#中通过Response.Headers设置自定义参数的代码示例》:本文主要介绍C#中通过Response.Headers设置自定义响应头的方法,涵盖基础添加、安全校验、生产实践及调试技巧,强... 目录一、基础设置方法1. 直接添加自定义头2. 批量设置模式二、高级配置技巧1. 安全校验机制2. 类型

C#使用iText获取PDF的trailer数据的代码示例

《C#使用iText获取PDF的trailer数据的代码示例》开发程序debug的时候,看到了PDF有个trailer数据,挺有意思,于是考虑用代码把它读出来,那么就用到我们常用的iText框架了,所... 目录引言iText 核心概念C# 代码示例步骤 1: 确保已安装 iText步骤 2: C# 代码程

C#实现高性能拍照与水印添加功能完整方案

《C#实现高性能拍照与水印添加功能完整方案》在工业检测、质量追溯等应用场景中,经常需要对产品进行拍照并添加相关信息水印,本文将详细介绍如何使用C#实现一个高性能的拍照和水印添加功能,包含完整的代码实现... 目录1. 概述2. 功能架构设计3. 核心代码实现python3.1 主拍照方法3.2 安全HBIT

C#实现SHP文件读取与地图显示的完整教程

《C#实现SHP文件读取与地图显示的完整教程》在地理信息系统(GIS)开发中,SHP文件是一种常见的矢量数据格式,本文将详细介绍如何使用C#读取SHP文件并实现地图显示功能,包括坐标转换、图形渲染、平... 目录概述功能特点核心代码解析1. 文件读取与初始化2. 坐标转换3. 图形绘制4. 地图交互功能缩放

C#使用SendMessage实现进程间通信的示例代码

《C#使用SendMessage实现进程间通信的示例代码》在软件开发中,进程间通信(IPC)是关键技术之一,C#通过调用WindowsAPI的SendMessage函数实现这一功能,本文将通过实例介绍... 目录第一章:SendMessage的底层原理揭秘第二章:构建跨进程通信桥梁2.1 定义通信协议2.2

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很