Replacing the Visual Studio Select Resource Dialog Box

In my project I have over 750 images in a resource. Using VS built into the Select Resource dialog is a nightmare to find and select a single image - let them say - per button in the winforms designer.

It would be much more convenient if it was some kind of explorer-like dialog and that lack of search functionality.

  • Do you have an idea to replace this dialogue?

  • Is there any extension that can do this?

  • If there is no such extension, I would create an extension / add-on, which is what I need to do. Do you have any real experience, if it can be done at all?

  • I thought I would find a suitable DLL and extend it beaviour but unfortunately I cannot find which DLL contains this tragedy

Any help would be appreciated, thanks!

+3


source to share


1 answer


Resource selection dialog box - UITypeEditor

. It is an inner class ResourceEditorSwitch<T>

that uses an inner class internally ResourcePickerDialog

, and both are in an assembly Microsoft.VisualStudio.Windows.Forms.dll

, which is one of the assemblies of a Visual Studio assembly.

Since the implementation of the class is closely related to some of the other internal classes of the Visual Studio compilations, so it is difficult to extract the source code and customize it, but you have such information about the class that will help us take a look in its source code and give us more information about the class.

To customize the resource selection dialog. Instead, you can get an instance of the class at design time, and before displaying the dialog, process the dialog using code to have a filtering function like the following gif, note TextBox

that I'm 'added to the dialog:

enter image description here

You can filter ListBox

by typing TextBox

and using keys โ†‘and โ†“without changing focus from TextBox

, you can select filtered results.

To do this, you need:



  • Create ControlDesigner

    and register it as the constructor for your control. Then in, OnCreateHandle

    find the property you are going to edit. For example BackgroundImage

    .
  • Find UITypeEditor

    this property. The editor is of the type ResourceEditorSwitch<T>

    that the instance uses ResourcePickerDialog

    . Get a copy for ResourcePickerDialog

    .
  • Get the field resourcePickerUI

    and instantiate the dialog resourcePickerUI

    . This is a dialogue that you must change. The dialog contains several TableLayoutPanel

    . You have to paste TextBox

    in a suitable place and handle the event TextChanged

    and filter the values โ€‹โ€‹that are displayed in ListBox

    . All controls are named and you can simply access them and change their properties and values.

  • After changing the shape, assign it resourcePickerUI

    . This way the editor will use the modified form and show you what you need.

Implementation

You can find a complete working example in the following repository:

Here's the code for the designer:

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();
    }
}

      

0


source







All Articles