【问题标题】:Displaying available strongly typed resource classes in Property Window在属性窗口中显示可用的强类型资源类
【发布时间】:2008-12-03 20:14:21
【问题描述】:

我正在扩展 Gridview Web 控件,这是我第一次尝试创建自定义控件。

作为扩展的一部分,我将网格列标题的本地化封装在控件中。其中,我公开了几个属性来启用此功能:

bool AutoLocalizeColumnHeaders - 启用该功能

string HeaderResourceFile - 标识一个强类型资源类,从中获取标题文本

我正在重写 OnRowDataBound 处理程序并使用反射获取适当的 ResourceManager 来填充标题文本。这一切都很好,但我想在属性窗口中显示一个可用的强类型资源类列表供用户选择,而不是他们必须手动输入名称。

我创建了一个 TypeConverter 用于显示一个下拉列表,在该下拉列表中显示可用的类,但不知道如何获取要显示的可用类名列表?

我已经尝试了很长时间,但没有成功,我已经快要失去理智了。我假设必须有某种方法可以使用反射来实现这一点?

【问题讨论】:

    标签: asp.net custom-server-controls design-time


    【解决方案1】:

    我想我现在找到了解决方案。

    在 Page_Load 事件中运行以下命令给了我资源类名称:

    String[] resourceClassNames = (from type in assembly.GetTypes()
       where type.IsClass && type.Namespace.Equals("Resources")
       select type.Name).ToArray();
    

    所以我认为我可以从 TypeConverter 的 GetResourceFileNames(ITypeDescriptorContext context) 函数内部执行类似的操作,使用 context 参数来获取正确的程序集。不幸的是,我似乎只能获得自定义控件的程序集或 System.Web 程序集。

    因此,我创建了一个 UITypeEditor,它具有一个传递给 EditValue 例程的 IServiceProvider。由此我能够创建一个 ITypeDiscoveryService 实例,然后我用它从正确的程序集中获取所有类型:

    public override object EditValue(ITypeDescriptorContext context, 
                                     IServiceProvider provider, object value)
    {
        // Check if all the expected parameters are here
        if (context == null || context.Instance == null || provider == null)
        {
            // returning with the received value
            return base.EditValue(context, provider, value);
        }
    
        // Create the Discovery Service which will find all of the available classes
        ITypeDiscoveryService discoveryService = (ITypeDiscoveryService)provider.GetService(typeof(ITypeDiscoveryService));
        // This service will handle the DropDown functionality in the Property Grid
        _wfes = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService;
    
        // Create the DropDown control for displaying in the Properties Grid
        System.Windows.Forms.ListBox selectionControl = new System.Windows.Forms.ListBox();
        // Attach an eventhandler to close the list after an item has been selected
        selectionControl.SelectedIndexChanged += new EventHandler(selectionControl_SelectedIndexChanged);
        // Get all of the available types
        ICollection colTypes = discoveryService.GetTypes(typeof(object), true);
        // Enumerate the types and add the strongly typed
        // resource class names to the selectionControl
        foreach (Type t in colTypes)
        {
            if (t.IsClass && t.Namespace.Equals("Resources"))
            {
                selectionControl.Items.Add(t.Name);
            }
        }
        if (selectionControl.Items.Count == 0)
        {
            selectionControl.Items.Add("No Resources found");
        }
        // Display the UI editor combo
        _wfes.DropDownControl(selectionControl);
    
        // Return the new property value from the UI editor combo
        if (selectionControl.SelectedItem != null)
        {
            return selectionControl.SelectedItem.ToString();
        }
        else
        {
            return base.EditValue(context, provider, value);
        }
    }
    
    void selectionControl_SelectedIndexChanged(object sender, EventArgs e)
    {
        _wfes.CloseDropDown();
    }
    

    这似乎运作良好,虽然我希望有一种更时尚的方式来获取使用 LinQ 所需的类型,但我才刚刚开始研究 LinQ,并且在查询集合时似乎无法获得正确的语法而不是前面例子中的数组。

    如果有人可以建议可以做到这一点的 LinQ 语法,或者确实是完成整个事情的更好方法,那么它将是最受欢迎的。

    【讨论】:

      【解决方案2】:

      有趣的想法。我想您的属性当前设置为字符串? 我想知道您是否将您的属性设置为枚举,然后使用强类型资源类创建一个枚举,它是否足够聪明以在属性窗口中显示它们。它足够聪明,可以在后面的代码中显示它,看不出为什么它不能在属性窗口中加载它。

      【讨论】:

        【解决方案3】:

        在我之前发布的解决方案中,我想找到一种使用 LinQ 执行以下操作的方法:

            // Get all of the available types
            System.Collections.ICollection colTypes = discoveryService.GetTypes(typeof(object), true);
            // Enumerate the types and add the strongly typed resource class names to the selectionControl
            foreach (Type t in colTypes)
            {
                if (t.IsClass && t.Namespace.Equals("Resources"))
                {
                    selectionControl.Items.Add(t.Name);
                }
            }
        

        这似乎是做生意:

            // Get all of the available class names from the Resources namespace
            var resourceClassNames = from Type t in discoveryService.GetTypes(typeof(object), true)
                                where t.IsClass && t.Namespace.Equals("Resources")
                                select t.Name;
        
            selectionControl.Items.AddRange(resourceClassNames.ToArray());
        

        它看起来确实干净多了,我猜它的性能会更好,因为它没有循环遍历所有可用的类型,检查符合我代码中标准的类型;虽然我认为 LinQ 会为我做这件事,尽管是以更有效的方式?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-10-12
          • 2019-09-30
          • 1970-01-01
          • 1970-01-01
          • 2012-09-30
          相关资源
          最近更新 更多