Стандартизация поведения окон программы
От: Ghjcnjbvz  
Дата: 23.09.10 08:08
Оценка:
Приветствую,

Занимаюсь поддержкой одного старого проекта и задался таким вопросом:
как лучше стандартизировать поведение всех окон и элементов интерфейса в программе?
И главное как все это оптимизировать в случае разработки на C# под VS.

Для примера: все окна должны поддерживать закрытие по нажатию ESC и выполнение какого-то действия (каждое окно свое) по нажатию Enter, все окна предпросмотра при печати должны поддерживать навигацию по стрелкам на клавиатуре и изменение масштаба при скроллировании колесиком мышки, все комбобоксы и листбоксы должны вместо стандартной автоподстановки должны при ручном вводе предлагать возможные варианты (алгоритм тоже зависит от контекста).

Первая мысль — сделать свои собственные компоненты на основе стандартных, но проблема в том что уже задействовано много сторонних библиотек компонентов.

Вручную проверять каждую форму и каждый элемент управления — долго и непродуктивно. Постоянно кто-то что-то да забудет добавить.
Re: Стандартизация поведения окон программы
От: skodnik  
Дата: 23.09.10 10:06
Оценка:
Здравствуйте, Ghjcnjbvz, Вы писали:
G>все окна должны поддерживать закрытие по нажатию ESC и выполнение какого-то действия (каждое окно свое) по нажатию Enter,
наследование + виртуальный метод
Re: Стандартизация поведения окон программы
От: RushDevion Россия  
Дата: 23.09.10 10:32
Оценка:
Я бы предложил такой подход (только в качестве идеи).
Пишем классы поведения, каждый из которых отвечает за какой-то аспект поведения контрола (подписавшись на соотв. события)
Скажем CloseOnEsc(Form form) и т.п.
Делаем базовую форму с абстрактным методом, в потомках применяем нужное поведение к нужным контролам.
Понятное дело, такой подход применим если требуемого поведения можно добиться через публичный интерфейс соотвествующего контрола,
иначе без наследования никак не получится обойтись.

И примерчик:
public partial class SomeForm : Form
    {
        ArrayList behaviors = new ArrayList();

        public SomeForm()
        {
            InitializeComponent();            
        }

        protected override void OnHandleCreated( EventArgs e )
        {
            base.OnHandleCreated( e );
            behaviors.Clear();
            behaviors.Add( new CloseOnEsc( this ) );
            behaviors.Add( new ComboBoxPrompt( comboBox1, ProvidePrompts ) );
        }

        protected override void OnHandleDestroyed( EventArgs e )
        {
            for ( int i = behaviors.Count - 1; i >= 0; --i )
            {
                IDisposable disp = behaviors[i] as IDisposable;
                if ( null != disp )
                    disp.Dispose();
                behaviors.RemoveAt( i );
            }
            base.OnHandleDestroyed( e );
        }

        IEnumerable<string> ProvidePrompts( string str )
        {
            if ( str.StartsWith( "A" ) )
            {
                yield return "AA";
                yield return "AAAA";
                yield return "AAAAAA";
            }
        }        
    }

    public sealed class CloseOnEsc : IDisposable
    {
        readonly SomeForm Target;
        bool disposed;

        public CloseOnEsc( SomeForm form )
        {
            Target = form;
            Target.PreviewKeyDown += Target_PreviewKeyDown;
        }

        public void Dispose()
        {
            if ( !disposed )
            {
                Target.PreviewKeyDown -= Target_PreviewKeyDown;
                disposed = true;
            }
        }

        void Target_PreviewKeyDown( object sender, PreviewKeyDownEventArgs e )
        {
            if ( e.KeyCode == Keys.Escape )
            {
                Target.Close();
            }
        }
    }

    public sealed class ComboBoxPrompt : IDisposable
    {
        readonly ComboBox Target;
        Func<string, IEnumerable<string>> GetVariants;
        bool disposed;

        public ComboBoxPrompt( ComboBox cb, Func<string, IEnumerable<string>> getVariants )
        {
            Target = cb;
            Target.TextChanged += Target_TextChanged;
            GetVariants = getVariants;
        }

        void Target_TextChanged( object sender, EventArgs e )
        {
            string text = Target.Text ?? "";
            IEnumerable ie = GetVariants( text );
            Target.BeginUpdate();
            Target.Items.Clear();
            foreach ( string str in ie )
                Target.Items.Add( str );
            Target.EndUpdate();
            Target.Select( text.Length, 0 );
        }

        public void Dispose()
        {
            if ( !disposed )
            {
                Target.TextChanged -= Target_TextChanged;
                disposed = true;
            }
        }
    }
Re[2]: Стандартизация поведения окон программы
От: Ghjcnjbvz  
Дата: 23.09.10 14:30
Оценка:
Здравствуйте, skodnik, Вы писали:

S>Здравствуйте, Ghjcnjbvz, Вы писали:

G>>все окна должны поддерживать закрытие по нажатию ESC и выполнение какого-то действия (каждое окно свое) по нажатию Enter,
S>наследование + виртуальный метод

проблема в том что в этой солянке часть окон наследуется от стандартных компонентов, а часть от самописных\сторонних.
получается надо сделать несколько родителей от которых потом уже наследовать. несколько упрощает работу, но количество всяких элементов для которых придется создавать своих собственных предков весьма велико.
Re[2]: Стандартизация поведения окон программы
От: Ghjcnjbvz  
Дата: 24.09.10 10:44
Оценка:
Спасибо, надо будет подумать над идеей.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.