Splitter Changes Not Working Correctly in DPI Aware App

3 posts, 0 answers
  1. Robert
    Robert avatar
    14 posts
    Member since:
    Dec 2015

    Posted 23 Aug Link to this post

    Hello,

    There appears to be an issue making tool window width adjustments via the splitters in a DPI aware app. Dragging a splitter with the mouse will eventually hide the document window as the tool window makes large changes when only small changes are wanted. This can be demonstrated with a new app with a RadDock control dropped on the form. Add 2 tool windows and 1 document window. Make the app DPI aware. Run the app at 150% and try making small width changes to either of the tool windows. The tool window will make a couple of large jumps and then completely hide the document window. It also doesn't matter which way you drag the tool window as the same phenomenon occurs.

    Telerik Control Version: 2017.2.613.40

    Framework 4.52 or higher.

    Best regards,

    Robert

     

     

     

  2. Hristo
    Admin
    Hristo avatar
    1018 posts

    Posted 25 Aug Link to this post

    Hi Robert,

    Thank you for writing.

    I managed to reproduce the incorrect behavior and I have logged the issue on our feedback portal, here: FIX. RadDock - the tool windows are not resized correctly in higher DPI. You can additionally subscribe to it and be updated with all of its status changes. I have also updated your Telerik points.

    The item is already in development and a fix will be introduced with our R3 release scheduled for mid-September. Until then you will need to create a custom RadDock with a custom layout strategy: 
    public class MyRadDock : RadDock
    {
        public override string ThemeClassName
        {
            get
            {
                return typeof(RadDock).FullName;
            }
        }
     
        protected override SplitContainerLayoutStrategy CreateLayoutStrategy()
        {
            MySplitContainerLayoutStrategy strategy = null;
            if (this.LayoutStrategyType != null)
            {
                try
                {
                    strategy = Activator.CreateInstance(this.LayoutStrategyType) as MySplitContainerLayoutStrategy;
                }
                catch
                {
                    strategy = null;
                }
            }
     
            if (strategy == null)
            {
                strategy = new MySplitContainerLayoutStrategy();
            }
     
            strategy.RootContainerType = typeof(RadDock);
            return strategy;
        }
    }
     
    public class MySplitContainerLayoutStrategy : SplitContainerLayoutStrategy
    {
        protected override void Measure()
        {
            SplitContainerLayoutInfo layoutInfo = (SplitContainerLayoutInfo)typeof(SplitContainerLayoutStrategy).GetField("layoutInfo", BindingFlags.Instance | BindingFlags.NonPublic).
                GetValue(this);
     
            SplitPanel fillPanel = (SplitPanel)typeof(SplitContainerLayoutInfo).GetField("fillPanel", BindingFlags.Instance | BindingFlags.NonPublic).
                GetValue(layoutInfo);
     
            if (fillPanel == null)
            {
                base.Measure();
            }
     
            this.MeasureWithFillPanel();
     
            typeof(SplitContainerLayoutStrategy).GetMethod("ClampMeasuredLength", BindingFlags.Instance | BindingFlags.NonPublic).
                Invoke(this, new object[] { });
        }
     
        private void MeasureWithFillPanel()
        {
            FieldInfo layoutInfoFi = typeof(SplitContainerLayoutStrategy).GetField("layoutInfo", BindingFlags.Instance | BindingFlags.NonPublic);
            SplitContainerLayoutInfo layoutInfo = (SplitContainerLayoutInfo)layoutInfoFi.GetValue(this);
     
            int availableLength = (int)typeof(SplitContainerLayoutInfo).GetField("availableLength", BindingFlags.Instance | BindingFlags.NonPublic).
              GetValue(layoutInfo);
     
            int remaining = availableLength;
            SplitPanel panel;
     
            //calculate the desired size of all non-fill panels
            int desiredNonFillLength = 0;
     
            List<SplitPanel> layoutTargets = (List<SplitPanel>)typeof(SplitContainerLayoutInfo).GetField("layoutTargets", BindingFlags.Instance | BindingFlags.NonPublic).
                GetValue(layoutInfo);
     
            SplitPanel fillPanel = (SplitPanel)typeof(SplitContainerLayoutInfo).GetField("fillPanel", BindingFlags.Instance | BindingFlags.NonPublic).
                  GetValue(layoutInfo);
     
            int count = layoutTargets.Count;
            for (int i = 0; i < count; i++)
            {
                panel = layoutTargets[i];
                if (panel == fillPanel)
                {
                    continue;
                }
     
                desiredNonFillLength += this.GetLength(panel.SizeInfo.AbsoluteSize);
            }
     
            SplitPanelSizeInfo fillInfo = fillPanel.SizeInfo;
     
            int totalSplitterLength = (int)typeof(SplitContainerLayoutInfo).GetField("totalSplitterLength", BindingFlags.Instance | BindingFlags.NonPublic).
                  GetValue(layoutInfo);
            int layoutableLength = availableLength - totalSplitterLength;
            int correction = 0;
     
            int totalMinLength = (int)typeof(SplitContainerLayoutInfo).GetField("totalMinLength", BindingFlags.Instance | BindingFlags.NonPublic).
                  GetValue(layoutInfo);
     
            int desiredFillLength = totalMinLength;
            if (desiredNonFillLength + desiredFillLength > layoutableLength)
            {
                correction = (desiredNonFillLength + desiredFillLength) - layoutableLength;
            }
     
            int remainingCorrection = correction;
            for (int i = 0; i < layoutTargets.Count; i++)
            {
                panel = layoutTargets[i];
                if (panel == fillPanel)
                {
                    continue;
                }
     
                int length = this.GetLength(TelerikDpiHelper.ScaleSize(panel.SizeInfo.AbsoluteSize, new SizeF(1f / panel.SplitPanelElement.DpiScaleFactor.Width, 1f / panel.SplitPanelElement.DpiScaleFactor.Height)));
                if (remainingCorrection > 0 && panel.SizeInfo.SizeMode != SplitPanelSizeMode.Absolute)
                {
                    float factor = (float)length / desiredNonFillLength;
                    int panelCorrection = Math.Max(1, (int)(factor * correction));
                    remainingCorrection -= panelCorrection;
                    length -= panelCorrection;
                }
     
                panel.SizeInfo.MeasuredLength = length;
                int splitterLength = (int)typeof(SplitContainerLayoutInfo).GetField("splitterLength", BindingFlags.Instance | BindingFlags.NonPublic).
                 GetValue(layoutInfo);
                remaining -= (panel.SizeInfo.MeasuredLength + splitterLength);
            }
             
            fillPanel.SizeInfo.MeasuredLength = remaining;
        }
    }

    I am also sending you attached my test project.

    I hope this helps. Should you have further questions please do not hesitate to write back.

    Regards,
    Hristo
    Progress Telerik
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  3. Robert
    Robert avatar
    14 posts
    Member since:
    Dec 2015

    Posted 30 Aug in reply to Hristo Link to this post

    I have tried out your temporary work around and it does the job quite nicely. Thank you.

    Robert

     

Back to Top