Я расширяю веб-элемент управления Gridview в качестве первой попытки создания настраиваемого элемента управления.
В рамках расширения я инкапсулирую локализацию заголовков столбцов сетки в элементе управления. Среди прочего, я раскрываю несколько свойств, чтобы включить эту функцию:
bool AutoLocalizeColumnHeaders - включает функцию
string HeaderResourceFile - определяет строго типизированный класс ресурсов, из которого следует получить текст заголовка
Я переопределяю обработчик OnRowDataBound и получаю соответствующий ResourceManager с помощью Reflection для заполнения текста заголовка. Все это работает хорошо, но я хотел бы отобразить список доступных строго типизированных классов ресурсов в окне свойств, чтобы пользователь мог выбирать из них, вместо того, чтобы вводить имя вручную.
Я создал TypeConverter для отображения раскрывающегося списка, в котором отображаются доступные классы, но не могу понять, как получить список доступных имен классов для отображения?
Я уже довольно давно безуспешно пытаюсь и вот-вот потеряю рассудок. Я предполагаю, что должен быть какой-то способ добиться этого с помощью Reflection?





Интересная идея. Я полагаю, что ваша собственность в настоящее время задана как строка? Интересно, если вы установите свое свойство как Enum, а затем создадите Enum со строго типизированными классами ресурсов, будет ли оно достаточно умным, чтобы отображать их в окне свойств. он достаточно умен, чтобы показать его в коде позади, не может понять, почему он не может загрузить его в окне свойств.
Думаю, теперь я нашел решение.
Выполнение следующего из события Page_Load дало мне имена классов ресурсов:
String[] resourceClassNames = (from type in assembly.GetTypes()
where type.IsClass && type.Namespace.Equals("Resources")
select type.Name).ToArray();
Поэтому я подумал, что смогу сделать что-то подобное внутри функции GetResourceFileNames (ITypeDescriptorContext context) TypeConverter, используя параметр 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, который сделает это или, действительно, лучший способ выполнить все это, то это будет очень приветствоваться.
В моем решении, опубликованном ранее, я хотел найти способ сделать следующее с помощью 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 сделает это за меня, хотя и более эффективным способом?