Snap Window Behavior

  • 5 minutes to read

The Snap Window Behavior allows you to implement sticky windows that snap to other windows and screen edges.

Behaviors - Snap Forms

The behavior also supports custom snap zones, which means you can manually specify regions to which your sticky windows should be able to snap.

Supported controls

Behavior options

  • SnapToScreen - specifies whether or not the target control can snap to screen edges.
  • SnapToControls - specifies whether or not the target control can snap to other snap objects (see below).
  • SnapThreshold - when a distance in pixels between a target control and a snap zone reaches this value, the target control will be snapped.
  • SnapOnMoving - if enabled, the target control will snap to available snap regions on the move (when end-users drag this control).
  • SnapOnResizing - if enabled, the target control will snap to available snap regions when end-users resize it.

    Behaviors - Snap Resize

Enable Window Snapping for Separate Forms

When you attach a snap window behavior to any standard or DevExpress form, you actually do two things:

  • provide this form with a variety of options that specify how and when this form itself will be able to snap;
  • declare this form as a snap zone to which other sticky forms can snap (if their own behavior options allow them so).

Based on these two statements, the following is true.

  • A form that is the only one with a snap window behavior attached can by default snap only to screen edges, since no other snap zones are present.
  • To be able to snap multiple forms to each other, attach a behavior to each one of them.
  • You can attach a snap window behavior to a form and disable all of its snapping options. In this case, the form will not be able to snap anywhere. However, other sticky forms will still recognize it as a snap zone and will be able to snap to it.

Provide Custom Snap Zones For Sticky Windows

Default snapping options allow sticky windows to snap to screen edges and other windows of their kind. You can also supply sticky windows with custom snap zones to which these windows will be able to snap.

The animation below illustrates a sample: main form contains four labels that act as custom snap zones. The child form is able to snap to these custom zones.

Behaviors - Custom Snap Zones

To make this setup work, do the following.

  • Define rectangular snap zones to which sticky windows will be able to snap. In this sample scenario, snap zones match the label controls' bounds. Same bounds can be used to draw dashed borders around labels to clearly visualize them as snap zones.

    
    public SnapForm1() {
        InitializeComponent();
        this.ResizeBegin += (s, e) => { this.SuspendLayout(); };
        this.ResizeEnd += (s, e) => { this.ResumeLayout(true); this.Invalidate(); };
    }
    
    
    protected override void OnPaint(PaintEventArgs e) {
        base.OnPaint(e);
        Pen customPen = new Pen(Color.FromArgb(60, 60, 60));
        customPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
        customPen.DashCap = System.Drawing.Drawing2D.DashCap.Flat;
        customPen.DashPattern = new float[] { 2, 4 };
        using (DevExpress.Utils.Drawing.GraphicsCache cache = new DevExpress.Utils.Drawing.GraphicsCache(e.Graphics)) {
            cache.DrawRectangle(customPen, labelControl1.Bounds);
            cache.DrawRectangle(customPen, labelControl2.Bounds);
            cache.DrawRectangle(customPen, labelControl3.Bounds);
            cache.DrawRectangle(customPen, labelControl4.Bounds);
        }
    }
    
  • In the host form's code, define public properties that will allow you to retrieve snap zones from outside. Call the Control.PointToScreen method to retrieve screen coordinates instead of form coordinates.

    
    public Rectangle SnapZone1
    {
        get { return new Rectangle(labelControl1.PointToScreen(Point.Empty), labelControl1.Size); }
    }
    
    public Rectangle SnapZone2
    {
        get { return new Rectangle(labelControl2.PointToScreen(Point.Empty), labelControl2.Size); }
    }
    
    public Rectangle SnapZone3
    {
        get { return new Rectangle(labelControl3.PointToScreen(Point.Empty), labelControl3.Size); }
    }
    
    public Rectangle SnapZone4
    {
        get { return new Rectangle(labelControl4.PointToScreen(Point.Empty), labelControl4.Size); }
    }
    
  • Retrieve the default snap window helper and customize its snap zone collection. To do so, access the static Default property of the DevExpress.Utils.Controls.SnapWindowHelper class and handle its QuerySnapRectangles event. In the event handler, modify the QuerySnapRectanglesEventArgs.CustomRectangles collection as required.

    
    using DevExpress.Utils.Controls;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace SnapBehavior {
        public partial class SnapForm1: XtraForm {
            public SnapForm1() {
                InitializeComponent();
                //handle this event to add and remove custom snap zones
                SnapWindowHelper.Default.QuerySnapRectangles += Default_QuerySnapRectangles;
            }
    
            private void Default_QuerySnapRectangles(object sender, QuerySnapRectanglesEventArgs e) {
                //the event is raised each time a sticky window moves,
                //so you can ensure the collection is populated with valid rectangles every time this happens
                e.CustomRectangles.Clear();
                e.CustomRectangles.AddRange(new Rectangle[] {
                    this.SnapZone1,
                    this.SnapZone2,
                    this.SnapZone3,
                    this.SnapZone4 });
            }
        }
    }