CodeFluent Aspect: Как настроить ввод DropDown со свойствами объекта

Я разрабатываю аспект полнотекстового индекса и дошел до того, что я могу указать свойство, которое будет полнотекстовым индексом.

Однако следующее, что я хочу сделать, - это указать в синтаксисе полнотекстового индекса SQL "TYPE COLUMN xx", где "xx" - другое свойство того же объекта.

В связи с этим я хотел бы спросить аспекты CodeFluent, как мне настроить раскрывающийся список всех других постоянных свойств для текущей сущности для входных данных аспекта?

Вот код CodeFluent Aspect XML, который у меня есть:

        static FullTextIndexing()
        {
            Descriptor = new XmlDocument();
            Descriptor.LoadXml(
@"<cf:project xmlns:cf='http://www.softfluent.com/codefluent/2005/1' defaultNamespace='FullTextIndexing'>
    <cf:pattern name='Full Text Indexing' namespaceUri='" + NamespaceUri + @"' preferredPrefix='ftind' step='Tables'>
        <cf:message class='_doc'>CodeFluent Full Text Indexing Aspect</cf:message>
        <cf:descriptor name='fullTextIndex'
            typeName='boolean'
            category='Full Text Index'
            targets='Property'
            defaultValue='false'
            displayName='Full-Text Index'
            description='Determines if property should be a full text index.' />
        <cf:descriptor name='fullTextIndexTypeColumn'
            typeName='text'
            category='Full Text Index'
            targets='Property'
            displayName='Type Column'
            description='The type column for the full text index.' />
    </cf:pattern>
</cf:project>");
        }

Это дает мне "текстовое поле". То, что я хочу, это раскрывающийся список других свойств той же сущности.

CodeFluent Изображение Аспектных Входов

Редактировать один:

Я пытался использовать UITypeEditor, чтобы сделать раскрывающийся список, но, похоже, он не работает. "Тип столбца" неактивен и имеет черный ящик.

Изображение ошибки редактора типов

Я могу сделать что-то не так.

Мой пользовательский класс UITypeEditor выглядит следующим образом:

namespace CodeFluent.Aspects.AspectEditors
{
    public class OtherPropertyDropDownEditor : UITypeEditor
    {
        private IWindowsFormsEditorService _editorService;

        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            // drop down mode (we'll host a listbox in the drop down)
            return UITypeEditorEditStyle.DropDown;
        }

        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            _editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));

            // use a list box
            ListBox lb = new ListBox();
            lb.SelectionMode = SelectionMode.One;
            lb.SelectedValueChanged += delegate
            {
                // close the drop down as soon as something is clicked
                _editorService.CloseDropDown();
            };

            // use the Property.Name property for list box display
            lb.DisplayMember = "Name";

            // this is how we get the list of possible properties
            IEnumerable<Property> otherProperties = GetOtherPersistentProperties(context);
            foreach (Property otherProperty in otherProperties)
            {
                int index = lb.Items.Add(otherProperty);
                if (otherProperty.Equals(value))
                {
                    lb.SelectedIndex = index;
                }
            }


            // show this model stuff
            _editorService.DropDownControl(lb);
            if (lb.SelectedItem == null) // no selection, return the passed-in value as is
                return value;

            return lb.SelectedItem;
        }

        private IEnumerable<Property> GetOtherPersistentProperties(ITypeDescriptorContext context)
        {
            // context is of type ITypeDescriptorContext, got from EditValue overloads.
            var property = TypeNameEditor.GetObject<Property>(context);

            IEnumerable<Property> otherEntityProperties = null;
            if (property != null && property.Entity != null)
                otherEntityProperties = property.Entity.Properties.Where(p => p.IsPersistent && p != property);
            return otherEntityProperties;
        }
    }
}

XML у меня до сих пор это. Обратите внимание, что я добавил "editorTypeName".

        static FullTextIndexing()
        {
            Descriptor = new XmlDocument();
            Descriptor.LoadXml(
@"<cf:project xmlns:cf='http://www.softfluent.com/codefluent/2005/1' defaultNamespace='FullTextIndexing'>
    <cf:pattern name='Full Text Indexing' namespaceUri='" + NamespaceUri + @"' preferredPrefix='ftind' step='Tables'>
        <cf:message class='_doc'>CodeFluent Full Text Indexing Aspect</cf:message>
        <cf:descriptor name='fullTextIndex'
            typeName='boolean'
            category='Full Text Index'
            targets='Property'
            defaultValue='false'
            displayName='Full-Text Index'
            description='Determines if property should be a full text index.' />
        <cf:descriptor name='fullTextIndexTypeColumn'
            category='Full Text Index'
            targets='Property'
            editorTypeName='CodeFluent.Aspects.AspectEditors.OtherPropertyDropDownEditor, CodeFluent.Aspects.AspectEditors.OtherPropertyDropDownEditor, CodeFluent.Aspects.AspectEditors'
            displayName='Type Column'
            description='The type column for the full text index.'
            />
    </cf:pattern>
</cf:project>");
        }

1 ответ

Что вы можете сделать, это добавить атрибут xml в свой дескриптор для определения имени типа пользовательского TypeConverter, например:

<cf:descriptor name='fullTextIndexTypeColumn'
            typeName='text'
            category='Full Text Index'
            targets='Property'
            displayName='Type Column'
            description='The type column for the full text index.'
            typeConverterTypeName='ClassLibrary1.MyAspectConverter, ClassLibrary1'
            />

Затем вам нужно реализовать класс MyAspectConverter (здесь, в ClassLibrary1.dll), например, так:

public class MyAspectConverter : StringConverter
{
    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
    {
        return true;
    }

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        var list = new List<string>();
        var property = TypeNameEditor.GetObject<Property>(context);
        if (property != null && property.Entity != null)
        {
            list.AddRange(property.Entity.Properties.Where(p => p.IsPersistent).Select(p => p.Name));
        }
        return new StandardValuesCollection(list);
    }
}

ClassLibrary1 должен ссылаться CodeFluent.Runtime.dll, CodeFluent.Model.Common.dll а также CodeFluent.Model.dll (в общем из C:\Program Files (x86)\SoftFluent\CodeFluent\Modeler).

Вам нужно будет скопировать ClassLibrary1.dll который содержит этот конвертер в Visual Studio, откуда IDE может загрузить его, например, в C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE для Visual Studio 2015.

Обратите внимание: если вы определяете свой аспект в коде, вы можете поместить этот класс конвертера в ту же DLL, но вам всегда нужно будет копировать его в каталог Visual Studio.

Перезапустите Visual Studio, и вы должны увидеть что-то подобное в сетке свойств Visual Studio:

введите описание изображения здесь

Как указано в комментариях, вы также можете создать UITypeEditor, используя тот же принцип, если вам нужно более сложное редактирование (и использовать ' editorTypeName "Атрибут XML вместо" typeConverterTypeName атрибута), но он не нужен для списка строк.

Другие вопросы по тегам