Visual Studio“选择资源"对话框替换 [英] Visual Studio "Select Resource" dialog replacement
问题描述
在我的项目中,我有超过750张图像资源.使用内置在选择资源"对话框中的VS是为winforms设计器中的按钮查找和选择一个图像的噩梦,比如说.
In my project I have more than 750 images in resource. Using VS built in "Select Resource" dialog is a nightmare to find and select one image - let's say - for a button in winforms designer.
如果它是像对话框这样的资源管理器,并且缺少搜索功能,它将更加有用.
It would be much more usable if it was some explorer like dialog and it is lack of search functionality.
-
您是否知道如何替换此对话框?
Do you have any idea how to replace this dialog?
是否有任何扩展程序可以做到这一点?
Is there any extension that can do that?
如果没有这样的扩展名,我将创建一个扩展名/加载项.如果可以做到,您有任何实际经验吗?
If there is no such extension I would create an extension/add-in whatever I need to do. Do you have any real experience if it can be done at all?
我以为我会找到合适的dll并扩展其性能,但不幸的是,我找不到哪个dll包含此悲剧
I thought I will find the appropriate dll and extend its beaviour, but unfortunately I cannot find which dll contains this tragedy
任何帮助将不胜感激,谢谢!
Any help would be appreciated, thank you!
推荐答案
资源选择对话框是UITypeEditor
.内部类ResourceEditorSwitch<T>
是内部使用内部类ResourcePickerDialog
的内部类,它们都在Visual Studio的程序集之一的Microsoft.VisualStudio.Windows.Forms.dll
程序集中.
The Resource Select dialog is a UITypeEditor
. It is the internal class ResourceEditorSwitch<T>
which internally uses the internal class ResourcePickerDialog
and both of them are in Microsoft.VisualStudio.Windows.Forms.dll
assembly which is one of Visual Studio's assemblies.
由于该类的实现与Visual Studio程序集的其他一些内部类紧密相关,因此很难提取该类源代码并对其进行自定义,但是掌握这些类的相关信息将有助于我们了解一下它的源代码,让我们获得有关该类的更多信息.
Since the implementation of the class is tightly coupled with some other internal classes of Visual Studio's assemblies, so it's hard to extract the class source code and customize it, but you having those information about the class will help us to take a look at its source code and let us to have more information about the class.
自定义 Resource Select 对话框相反,您可以在设计时获取该类的实例,并且在显示对话框之前,使用代码操纵该对话框以具有类似gif,请注意我添加到对话框中的TextBox
:
To customize the Resource Select dialogInstead you can get an instance of the class at design time, and before showing the dialog, manipulate the dialog using code to have a filtering feature like following gif, pay attention to the TextBox
that I've added to the dialog:
您可以通过键入TextBox
并使用↑和↓键来过滤ListBox
,而无需从TextBox
更改焦点,您可以选择过滤的结果
You can filter the ListBox
by typing in TextBox
and using ↑ and ↓ keys, without changing the focus from TextBox
you can select filtered results.
为此,您应该:
- 创建一个
ControlDesigner
并将其注册为控件的设计者.然后在其OnCreateHandle
中找到要编辑的属性.例如BackgroundImage
. - 找到该属性的
UITypeEditor
.编辑器的类型为ResourceEditorSwitch<T>
,它使用ResourcePickerDialog
的实例.获取ResourcePickerDialog
的实例. -
获取
resourcePickerUI
字段并创建ResourcePickerUI
对话框的实例.这是您应该更改的对话框.该对话框包含一些TableLayoutPanel
.您应该在适当的位置插入TextBox
并处理其TextChanged
事件,并过滤ListBox
中显示的值.所有控件都有名称,您可以简单地访问它们并更改其属性和值.
- Create a
ControlDesigner
and register it as designer of your control. Then in itsOnCreateHandle
find the property which you are going to edit. For exampleBackgroundImage
. - Find the
UITypeEditor
of that property. The editor is of type ofResourceEditorSwitch<T>
which uses an instance ofResourcePickerDialog
. Get the instance forResourcePickerDialog
. Get the
resourcePickerUI
field and create an instance ofResourcePickerUI
dialog. It is the dialog that you should change. The dialog contains someTableLayoutPanel
. You should insert aTextBox
in a suitable place and handle itsTextChanged
event and filter the values which is showing in theListBox
. All controls have names and you can simply access to them and change their properties and values.
更改表格后,将其分配为resourcePickerUI
.这样,编辑器将使用更改后的表单并显示您需要的内容.
After changing the form, assign it resourcePickerUI
. This way, the editor will use the changed form and will show what you need.
实施
您可以在以下存储库中找到完整的工作示例:
You can find the full working example in the following repository:
这是设计师的代码:
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();
}
}
这篇关于Visual Studio“选择资源"对话框替换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!