4

在我的项目中,我有超过 750 张图片资源。使用 VS 内置的“选择资源”对话框是为 winforms 设计器中的按钮查找和选择一个图像的噩梦。

如果它是一些像对话框这样的浏览器并且它缺乏搜索功能,它会更有用。

  • 你知道如何替换这个对话框吗?

  • 有没有可以做到这一点的扩展程序?

  • 如果没有这样的扩展,我会创建一个扩展/加载项,无论我需要做什么。如果可以做到的话,你有什么真实的经验吗?

  • 我以为我会找到合适的dll并扩展它的行为,但不幸的是我找不到哪个dll包含这个悲剧

任何帮助将不胜感激,谢谢!

4

1 回答 1

1

资源选择UITypeEditor对话框是一个. 它是ResourceEditorSwitch<T>内部使用内部类的内部类ResourcePickerDialog,它们都在Microsoft.VisualStudio.Windows.Forms.dll程序集中,这是 Visual Studio 的程序集之一。

由于该类的实现与 Visual Studio 程序集的其他一些内部类紧密耦合,因此很难提取类源代码并对其进行自定义,但是您拥有有关该类的这些信息将有助于我们查看其源代码代码并让我们了解有关该类的更多信息。

要自定义资源选择对话框相反,您可以在设计时获取类的实例,在显示对话框之前,使用代码操作对话框以具有如下 gif 的过滤功能,注意TextBox我添加到对话框中的:

在此处输入图像描述

ListBox您可以通过输入TextBox和使用来过滤↑</kbd> and ↓</kbd> keys, without changing the focus from TextBox you can select filtered results.

为此,您应该:

  1. 创建一个ControlDesigner并将其注册为控件的设计器。然后在其中OnCreateHandle找到您要编辑的属性。例如BackgroundImage.
  2. 找到该UITypeEditor属性的。编辑器的类型是ResourceEditorSwitch<T>使用ResourcePickerDialog. 获取 的实例ResourcePickerDialog
  3. 获取resourcePickerUI字段并创建ResourcePickerUI对话框实例。这是您应该更改的对话框。该对话框包含一些TableLayoutPanel. TextBox您应该在合适的位置插入 a并处理其TextChanged事件并过滤显示在ListBox. 所有控件都有名称,您可以简单地访问它们并更改它们的属性和值。

  4. 更改表格后,分配它resourcePickerUI。这样,编辑器将使用更改后的表单并显示您需要的内容。

执行

您可以在以下存储库中找到完整的工作示例:

这是设计器的代码:

public class MyControlDesigner : ControlDesigner
{
    protected override void OnCreateHandle()
    {
        base.OnCreateHandle();
        var property = TypeDescriptor.GetProperties(this.Control)["BackgroundImage"];
        var resourceEditorSwitch = property.GetEditor(typeof(UITypeEditor)) as UITypeEditor;
        var editorToUseField = resourceEditorSwitch.GetType().GetProperty("EditorToUse",
            BindingFlags.NonPublic | BindingFlags.Instance);
        var editorToUse = editorToUseField.GetValue(resourceEditorSwitch);
        var resourcePickerUIField = editorToUse.GetType().GetField("resourcePickerUI",
            System.Reflection.BindingFlags.Instance |
            System.Reflection.BindingFlags.NonPublic);
        var resourcePickerUI = (Form)Activator.CreateInstance(resourcePickerUIField.FieldType);
        ModifyForm(resourcePickerUI);
        resourcePickerUIField.SetValue(editorToUse, resourcePickerUI);
    }
    void ModifyForm(Form f)
    {
        var resourceContextTableLayoutPanel = GetControl<TableLayoutPanel>(f, "resourceContextTableLayoutPanel");
        var resourceList = GetControl<ListBox>(f, "resourceList");
        resourceContextTableLayoutPanel.Controls.Remove(resourceList);
        var tableLayoutPanel = new TableLayoutPanel();
        tableLayoutPanel.Dock = DockStyle.Fill;
        tableLayoutPanel.Margin = new Padding(0);
        tableLayoutPanel.ColumnCount = 1;
        tableLayoutPanel.RowCount = 2;
        tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
        tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100));

        List<string> list = new List<string>();
        var textBox = new TextBox() { Dock = DockStyle.Fill, Margin = resourceList.Margin };
        Action<string> applyFilter = (s) =>
        {
            if (string.IsNullOrEmpty(s))
            {
                resourceList.BeginUpdate();
                resourceList.Items.Clear();
                resourceList.Items.AddRange(list.ToArray());
                resourceList.EndUpdate();
            }
            else
            {
                var list2 = list.Where(x => x.ToLower().StartsWith(s.ToLower())).ToList();
                resourceList.BeginUpdate();
                resourceList.Items.Clear();
                resourceList.Items.Add("(none)");
                resourceList.Items.AddRange(list2.ToArray());
                resourceList.EndUpdate();
            }
            if (resourceList.Items.Count > 1)
                resourceList.SelectedIndex = 1;
            else
                resourceList.SelectedIndex = 0;
        };
        var resxCombo = GetControl<ComboBox>(f, "resxCombo");
        resxCombo.SelectedValueChanged += (s, e) =>
        {
            resxCombo.BeginInvoke(new Action(() =>
            {
                if (resourceList.Items.Count > 0)
                {
                    list = resourceList.Items.Cast<string>().ToList();
                    textBox.Text = string.Empty;
                }
            }));
        };
        textBox.TextChanged += (s, e) => applyFilter(textBox.Text);
        textBox.KeyDown += (s, e) =>
        {
            if (e.KeyCode == Keys.Up)
            {
                e.Handled = true;
                if (resourceList.SelectedIndex >= 1)
                    resourceList.SelectedIndex--;
            }
            if (e.KeyCode == Keys.Down)
            {
                e.Handled = true;
                if (resourceList.SelectedIndex < resourceList.Items.Count - 1)
                    resourceList.SelectedIndex++;
            }
        };
        tableLayoutPanel.Controls.Add(textBox, 0, 0);

        resourceList.EnabledChanged += (s, e) =>
        {
            textBox.Enabled = resourceList.Enabled;

        };
        tableLayoutPanel.Controls.Add(resourceList, 0, 1);
        resourceContextTableLayoutPanel.Controls.Add(tableLayoutPanel, 0, 4);
    }
    T GetControl<T>(Control c, string name)
        where T : Control
    {
        return (T)c.Controls.Find(name, true).FirstOrDefault();
    }
}
于 2017-12-03T05:03:03.523 回答