понедельник, 24 сентября 2012 г.

Автоматическое изменение размеров FlowLayoutPanel в XtraLayoutControl (DevExpress)


[FlowLayoutPanel with autosize in XtraLayoutControl]

Работая с библиотекой элементов управления для WinForms от DevExpress в ходе практики накопилась небольшая тележка различных решений, обходных путей и просто интересных подходов. Со временем планирую их здесь опубликовать. Ну а пока, покажу, как я реализовал автоматическое изменение размеров FlowLayoutPanel в XtraLayoutControl, так чтобы все элементы, помещенные в FlowLayoutPanel, были всегда видны.

На рисунках отображен уже конечный результат, которого я хотел добиться:






XtraLayoutControl отлично управляет размерами и расположениями “своих” элементов управления из библиотеки DevExpress, но совершено не справляется со стандартными элементами управления, к которым относится FlowLayoutPanel. Дело в том, что XtraLayoutControl взаимодействует с элементами своеобразным образом и требует от элементов реализации специфичных интерфейсов. В нашем случае достаточно использовать интерфейс IXtraResizableControl, который я реализовал в унаследованном от панели классе:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DevExpress.XtraLayout;
using System.Drawing;
using DevExpress.Utils.Controls;

namespace WindowsFormsApplication9
{
    public class MyFlowLayoutPanel : FlowLayoutPanel, IXtraResizableControl
    {
        public MyFlowLayoutPanel() { // ctor
            
        }

        LayoutControl rootLayoutControl = null;
        LayoutControlItem parentControlItem = null;

        protected override void OnHandleCreated(EventArgs e) {
            base.OnHandleCreated(e);

            if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
                return;

            LayoutControl parent = this.Parent as LayoutControl;
            if (parent != null) {

                this.rootLayoutControl = parent;
                this.parentControlItem = FindItemByContentControl(parent.Root, this);

                CalcAndUpdateSize();
                this.rootLayoutControl.Resize += (x, y) => { CalcAndUpdateSize(); };
                this.ControlAdded += (x, y) => { CalcAndUpdateSize(); };
                this.ControlRemoved += (x, y) => { CalcAndUpdateSize(); };
            }
        }

        void layoutControl_Changing(object sender, EventArgs e) {
            CalcAndUpdateSize();
        }

        // REM. http://www.devexpress.com/Support/Center/p/Q396747.aspx (Hot to find a conatner LayoutcontrolItem of a control)
        LayoutControlItem FindItemByContentControl(LayoutControlGroup layoutGroup, Control contentControl) {

            foreach (BaseLayoutItem baseLI in layoutGroup.Items) {
                LayoutControlItem lci = baseLI as LayoutControlItem;
                if (lci != null && lci.Control == contentControl)
                    return lci;

                LayoutControlGroup lcg = baseLI as LayoutControlGroup;
                if (lcg != null)
                    return FindItemByContentControl(lcg, contentControl);
            }
                
            return null;
        }


        private void CalcAndUpdateSize() {
            if (parentControlItem == null || parentControlItem.ViewInfo == null) return;

            this.MaximumSize = new Size(parentControlItem.ViewInfo.ClientArea.Width, 0);
            RaiseSizeChanged();
        }

        #region IXtraResizableControl Member

        event EventHandler ChangedCore;
        event EventHandler IXtraResizableControl.Changed {
            add { ChangedCore += value; }
            remove { ChangedCore -= value; }
        }

        protected void RaiseSizeChanged() {
            if (ChangedCore != null) ChangedCore(this, EventArgs.Empty);
        }

        bool IXtraResizableControl.IsCaptionVisible { get { return false; } }

        Size IXtraResizableControl.MaxSize { get { return new Size(0, this.PreferredSize.Height); } }

        Size IXtraResizableControl.MinSize { get { return new Size(0, this.PreferredSize.Height); } }

        #endregion
    }
}

Ссылки по теме:

IXtraResizableControl Interface:
http://documentation.devexpress.com/#WindowsForms/clsDevExpressUtilsControlsIXtraResizableControltopic
FlowLayoutPanel with autosize and layout control:
http://www.devexpress.com/Support/Center/p/Q292593.aspx

Вот собственно и все. Исходный код можете скачать здесь

Комментариев нет: