在属性窗口中显示可用的强类型资源类

时间:2008-12-03 20:14:21

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

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

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

bool AutoLocalizeColumnHeaders - 启用功能

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

我正在覆盖OnRowDataBound处理程序并使用Reflection来获取相应的ResourceManager来填充标题文本。这一切都运行良好,但我想在属性窗口中显示可用的强类型资源类列表供用户选择,而不是他们必须手动输入名称。

我已经创建了一个TypeConverter来显示一个下拉列表,在该下拉列表中显示可用的类,但是无法确定如何获取要显示的可用类名列表?

我已经尝试了一段时间但现在没有成功,而且我正在失去理智。我假设必须有一些方法来实现这个使用Reflection?

3 个答案:

答案 0 :(得分: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参数来获取正确的程序集。不幸的是,我似乎只能获得Custom Control的程序集或System.Web程序集。

所以,我创建了一个UITypeEditor,它将一个IServiceProvider传递给EditValue例程。从这里我可以创建一个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语法可以做到这一点,或者确实是一种更好的方法来完成整个事情,那么这将是非常受欢迎的。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

在之前发布的解决方案中,我想找到一种方法来使用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会为我做这件事,虽然效率更高?