自定义 Combobox 控件自定义数据源,带有自定义 displaymember 和 valuemember

Posted

技术标签:

【中文标题】自定义 Combobox 控件自定义数据源,带有自定义 displaymember 和 valuemember【英文标题】:Custom Combobox control custom datasource with custom displaymember and valuemember 【发布时间】:2011-01-18 10:51:48 【问题描述】:

我正在开发一个继承自另一个组合框 (Janus UICombobox) 的自定义组合框控件。 我希望数据源基于 EntityType (LLBLGEN),这样当用户选择 EntityType 时,该 EntityType 的所有数据库记录都将加载到组合框中。

在我构建和运行时一切正常,但我也希望能够让用户有机会根据所选的 EntityType 选择 DisplayMember 和 ValueMember。

我有以下代码:

    public partial class DtUiComboBox : UIComboBox

    private Thread _loadThread;

    public DtUiComboBox()
    
        InitializeComponent();
    

    //Don't want this to be visible in the designer
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    public new object DataSource
    
        get;
        set;
    
    //Don't want this to be visible in the designer
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    public new string DisplayMember
    
        get;
        set;
    
    //Don't want this to be visible in the designer
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    public new string ValueMember
    
        get;
        set;
    
    //Don't want this to be visible in the designer
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    public new string DataMember
    
        get;
        set;
    

    //My Custom DisplayMember that should be based on the EntityFields from the selected EntityType
    [Category("Data")]
    public string DisplayField
    
        get;
        set;
    
    //My Custom ValueMember that should be based on the EntityFields from the selected EntityType
    [Category("Data")]
    public string ValueField
    
        get;
        set;
    

    private EntityType? _entityType;
    [Category("Data")]
    public EntityType? EntityTypeSource
    
        get
        
            return _entityType;
        
        set
        
            if (value != null)
            
                _entityType = value;
                IEntity2 entity2 = Dal.FactoryClasses.GeneralEntityFactory.Create(_entityType.Value);
                if (!DesignMode && !IsDesignerHost)
                
                    if (_loadThread != null && _loadThread.IsAlive)
                    
                        _loadThread.Abort();
                        _loadThread.Join(500);
                    
                    _loadThread = new Thread(new ThreadStart(LoadFromEntityType));
                    _loadThread.Start();
                
                Invalidate(true);
            
        
    

    private void LoadFromEntityType()
    
        if (_entityType.HasValue)
        
            IEntityCollection2 entityCollection = DtBlClient.Instance.Bl.GetCollection(_entityType.Value);
            LoadFromEntityType(entityCollection);
        
    

    private delegate void LoadFromEntityTypeDel(IEntityCollection2 collection2);
    private void LoadFromEntityType(object data)
    
        if (this.InvokeRequired)
        
            this.BeginInvoke(new LoadFromEntityTypeDel(LoadFromEntityType), data);
            return;
        
        DataSource = data;
    

    [BrowsableAttribute(false)]
    [Description("This method checks if I run in DesignMode, because Threading doesn't work in the Designer")]
    public bool IsDesignerHost
    
        get
        
            Control ctrl = this;

            while (ctrl != null)
            
                if ((ctrl.Site != null) && ctrl.Site.DesignMode)
                    return true;
                ctrl = ctrl.Parent;
            
            return false;
        
    

    [Browsable(false)]
    [Description("This method checks if I run in DesignMode, because Threading doesn't work in the Designer")]
    public new static bool DesignMode
    
        get
        
            string processName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;
            if (processName.Equals("devenv"))
                return true;
            return false;
        
    

我该怎么做?

【问题讨论】:

【参考方案1】:

如果您有两个用户可以在设计器(或代码)中设置的属性(即显示成员和值成员),您应该能够调用您的基类 (UIComboBox) 并将这些值设置为它们在基类中的等价物。

编辑(评论后):

This link 为您提供了两种获取给定实体的实体字段的方法(一种处理实体数据模型,第二种处理反射)。它解决了你一半的问题。但我不知道如何将此字段列表绑定到设计器...

【讨论】:

我理解那部分,但也许我的问题不够清楚,所以我会尝试解释:当用户选择 EntityType 时,我希望能够传递该实体的所有 EntityFields作为 DisplayMember 和 ValueMember 中的可选列表。【参考方案2】:

Net Framework 支持以多种方式自定义设计时行为。将属性和值提供给属性窗口的一种方法是通过 TypeConverter 对象。您可以通过实现自定义 TypeConverter 来实现这一点,但它还需要您装饰他们可能选择的所有类并为每个类提供类型转换器。

您可以通过创建自定义设计器对自定义控件的设计时行为的几乎任何方面进行广泛控制。自定义设计器将允许您跳过修改数据实体以供 UI 控件使用的半破解。相反,您可以构建自己的代码来探索实体(例如通过反射),然后根据您的选择填充属性窗口。创建自定义设计器并非易事,并且没有很好的文档记录。假设您不从事为零售市场制作控件的业务,这需要做很多工作,但如果您想要一个不受黑客攻击且可与任何数据实体一起使用的“专业”控件,那么定制设计器是您的最佳选择。

当然这将是一个不错的功能,但老实说,有多少属性甚至是这些参数的合适候选者。我几乎总是将“Id”作为值成员,而显示成员通常是“名称”顺序的东西。为数据绑定选择(并记住)字段往往是微不足道的,而您想要做的事情可能会被证明是乏味且耗时的。但是如果你想尝试......

没有人会一步一步地向您展示如何执行此操作,并且很难找到相关示例。当你冒险进入定制设计师时,你几乎是靠自己的。以下是一份技术概述文件,可帮助您开始研究这些技术:

http://msdn.microsoft.com/en-us/magazine/cc164048.aspx#S5

【讨论】:

以上是关于自定义 Combobox 控件自定义数据源,带有自定义 displaymember 和 valuemember的主要内容,如果未能解决你的问题,请参考以下文章

winform DataGridView 动态添加一列控件(自定义控件)

C# Winform自定义一个控件,一个按钮按下会显示ComboBox一样的下拉列表

WPF 自定义ComboBox下拉颜色控件

winform 自定义自动完成控件

在DataGrid中绑定自定义标头控件

自定义控件SelectedIndexChanged未触发