WinForm控件开发总结(八)-----为属性提供弹出式编辑对话框

      前几篇文章我们一直在讨论如何更方便的编辑复杂类型的属性,在这个过程中我介绍了类型转换器以及如何制作自己的类型转换器来实现属性值的串行化和实现子属性的编辑。对于Scope这种级别的复杂属性,一个类型转换器就已经足够了,但是对于更为复杂的属性,单单使用类型转换器已经不足以应付了,比如我们常用的Font属性。
       在这种情况下,我们就需要提供更为复杂的编辑方式,比如属性编辑对话框,你还记得Font对话框吗?现在我们就来看看如何实现更复杂的属性编辑。复杂的属性编辑器分为两种类型,一种是弹出式模态对话框属性编辑器,一种式下拉式属性编辑器。如果你还没有感性的认识的话,可以观察一下TextBox控件的属性,Font属性的编辑器是模态对话框属性编辑器,Dock属性的编辑器是下拉式属性编辑器。
       接下来我们来制作一个模态对话框编辑器,虽然Scope属性并不复杂,但是为了演示的方便,我们还是用它来做例子。
       首先我们要做一个用来编辑属性的对话框,在对话框的构造函数里传入要编辑的属性的值。在对话框类里,声明一个Scope类型的私有变量_scope用以保存传入和编辑后的值。还要增加一个Scope属性,以便外部环境能够获取编辑后的结果。对话框的外观如下: 
      
       在这个对话框里,我们要把OK按钮的DialogResult属性设为OK(当点击OK按钮时,模态对话框关闭,并返回DialogResult.OK),将Cancel按钮的DialogResult属性设为Cancel(当点击OK按钮时,模态对话框关闭,并返回DialogResult.OK)。另外我们要对用户输入的值做验证,以保证Scopeminmax值都是Int32类型。下边是对话框的代码:
      

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace CustomControlSample
{
    
public partial class ScopeEditorDialog : Form
    
{
        
private Scope _scope = null;

        
public ScopeEditorDialog(Scope scope)  
        
{
            InitializeComponent();
            _scope 
= scope;

            textBox1.Text 
= _scope.Min.ToString();
            textBox2.Text 
= _scope.Max.ToString();
        }


        
private void button1_Click(object sender, EventArgs e)
        
{
            _scope.Min 
= Convert.ToInt32(textBox1.Text);
            _scope.Max 
= Convert.ToInt32(textBox2.Text);
        }


        
private void textBox1_Validating(object sender, CancelEventArgs e)
        
{
            
try
            
{
                Int32.Parse(textBox1.Text);
                
            }

            
catch (FormatException)
            
{
                e.Cancel 
= true;
                MessageBox.Show(
"无效的值""验证错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }


        
private void textBox2_Validating(object sender, CancelEventArgs e)
        
{
            
try
            
{
                Int32.Parse(textBox2.Text);
            }

            
catch (FormatException)
            
{
                e.Cancel 
= true;
                MessageBox.Show(
"无效的值""验证错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }


        
public Scope Scope
        
{
            
get
            
{
                
return _scope;
            }

            
set
            
{
                _scope 
= value;
            }

        }

    }

}

         每一个属性的编辑器都是直接或者间接的派生于UITypeEditor。开发环境从来也不会直接调用我们编写的模态对话框来编辑属性,而是调用UITypeEditor的某些虚方法,所以我们还必须提供一个派生于UITypeEditor的类来与开发环境通信。下边的代码实现了Scope的编辑器:
      

using System;
using System.ComponentModel;
using System.Drawing.Design;
using System.Windows.Forms.Design;
using System.Windows.Forms;

namespace CustomControlSample
{
    
public class ScopeEditor:UITypeEditor
    
{
        
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        
{
            
if (context != null && context.Instance != null)
            
{
                
return UITypeEditorEditStyle.Modal;
            }


            
return base.GetEditStyle(context);
        }


        
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        
{
            IWindowsFormsEditorService editorService 
= null;

            
if (context != null && context.Instance != null && provider != null)
            
{
                editorService 
= (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
                
if (editorService != null)
                
{
                    MyListControl control 
= (MyListControl)context.Instance;
                    ScopeEditorDialog dlg 
= new ScopeEditorDialog(control.Scope);
                    
if (dlg.ShowDialog()== DialogResult.OK)
                    
{
                        value 
= dlg.Scope;
                        
return value;
                    }

                }

            }


            
return value;
        }

    }

}


       在这个类里,我们重写了两个方法,一个是GetEditStyle,在这个方法里,我们通知开发环境,属性的编辑器是一个模态对话框。另一个方法是EditValue,这是最核心的方法,在这个方法里,我们通过上下文环境获得了正在编辑的控件的实例,并将实例的Scope属性传递给属性编辑对话框,显示对话框供用户编辑属性的值,用户编辑完属性的值,并关闭对话框,这时,我们从对话框里获取编辑后的结果反会给开发环境。       编写完Editor,我们就要将它应用到MyListControlScope属性上,现在的Scope属性定义如下:
      
[Browsable(true)]
        [Editor(
typeof(ScopeEditor),typeof(UITypeEditor))]
        
public Scope Scope
        
{
            
get
            
{
                
return _scope;
            }

            
set
            
{
                _scope 
= value;
            }

        }

             我们在Scope属性前加上了[Editor(typeof(ScopeEditor),typeof(UITypeEditor))]元数据。Build工程,查看实际的效果。在测试工程的窗体上,选中控件,观察Scope属性,当我们单击Scope属性的值时,在属性值的后边出现了一个按钮,如图:
             

      当我们点击这个按钮后,弹出了属性编辑的对话框,如图:
      
      我们在对话框里编辑属性的值,并点击OK关闭对话框,现在Scope属性值已经被修改了。

posted on 2006-12-18 20:28 纶巾客 阅读(9184) 评论(19) 编辑 收藏

评论

#1楼 2006-12-18 21:13 mining lamp[未注册用户]

方法确实不错,有空试试看  回复 引用   

#2楼 2006-12-18 22:51 让风吹--笨牛      

不错啊,通俗易懂。
学习。
 回复 引用 查看   

#3楼 2006-12-19 09:53 Alan[匿名][未注册用户]

如果能附上源码,就更能方便初学者.呵呵.  回复 引用   

#4楼[楼主] 2006-12-19 11:11 纶巾客      

好主意,改天我把代码放上。  回复 引用 查看   

#5楼 2006-12-19 12:02 夜风[匿名][未注册用户]

是呀,把原码弄上,我按你步骤copy 代码,结果添加scopeconverter 后一编译就关掉vs2005  回复 引用   

#6楼 2006-12-19 19:54 niannian[未注册用户]

windows form 2.0 那本书里面的内容差不多。  回复 引用   

#7楼 2006-12-28 22:59 byby[未注册用户]

很好!不过,我在Scope属性的编辑Dialog中输入数据,然后接受数据关闭返回,在测试的WinForm的控件属性里,Scope值的确能显示出变化值,但是该WinForm并没有出现“*”被修改标记,保存该WinForm,退出,再次打开,Scope值还是原始值,说明并未被修改。这是为什么?  回复 引用   

#8楼 2007-03-09 17:12 需需      

讲解的条理很清析。  回复 引用 查看   

#9楼 2007-03-14 10:49 Louis.Lu.Sz      

问个问题,对于复杂的属性,如何设置默认值.
我搞了半天也没有成功.

 回复 引用 查看   

#10楼 2007-05-24 09:44 魏琼东      

请问,这样的方法能不能使用到类或其他对象上(非控件),我在界面上加了一个属性框,在运行时改变SelectObject参数,但是好像有问题,看不到弹出按钮  回复 引用 查看   

#11楼[楼主] 2007-05-24 23:03 纶巾客      

@魏琼东
这个不是针对控件的,是一种通用机制,你可以任何类上使用。
 回复 引用 查看   

#12楼 2007-10-13 14:52 snailsun[未注册用户]

我也遇到7楼的问题,使用Scope属性的编辑Dialog中输入数据后,WInform中的scope代码短没有变化还是旧的。而且经常报 Object reference not set to an
instance of an object.
 回复 引用   

#13楼 2009-09-12 15:04 minide      

当我点击
属性时,
未将对象应用到对象的实例
我却不能调试
 回复 引用 查看   

#14楼 2009-10-12 17:16 乱飞的云      

引用minide:
当我点击
属性时,
未将对象应用到对象的实例
我却不能调试


看一下楼主的11章,然后调试一下就知道问题了。  回复 引用 查看   

#15楼 2009-11-28 09:46 鹤冲天      

UITypeEditor,功能很强大!  回复 引用 查看   

#16楼 2010-08-05 13:48 烈火★寒冰      

收藏了  回复 引用 查看   

公告

本博客上的所有文章如非特别说明均为原创,如果要转载请注明文章出处。
昵称:纶巾客
园龄:6年3个月
粉丝:48
关注:0

导航

<2006年12月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

统计

  • 随笔 - 48
  • 文章 - 0
  • 评论 - 384
  • 引用 - 116

搜索

 
 

常用链接

我的标签

随笔分类(44)

随笔档案(48)

文章分类

联系我

友情链接

积分与排名

  • 积分 - 265322
  • 排名 - 280

最新评论

阅读排行榜

评论排行榜

推荐排行榜