簡體   English   中英

ScrollViewer不會滾動到自定義面板

[英]ScrollViewer doesn't scroll for custom panel

我正在制作自己的自定義面板,當內容不適合可用空間時,該面板應該垂直滾動,因此我將其放在ScrollViewer中。 現在,當內部面板大於ScrollViewer本身時,我無法使ScrollViewer激活滾動條。

permille函數具有附加的屬性,該屬性指示必須將孩子的大小與可用大小(不滾動)(又稱為ViewPort)進行比較。 由於在MeasureOverride中傳遞的大小會無限傳遞,所以我認為我無法在其中使用permille函數。 這就是為什么我在ArrangeOverride中衡量我的孩子們的原因(我猜這不是最佳實踐),但是那樣,scrollviewer不會滾動。

我該如何工作?

我的XAML代碼:

<ScrollViewer>
    <controls:TilePanel x:Name="TilePanel" PreviewMouseLeftButtonDown="TilePanel_PreviewMouseLeftButtonDown" PreviewMouseLeftButtonUp="TilePanel_PreviewMouseLeftButtonUp" 
                        PreviewMouseMove="TilePanel_PreviewMouseMove" DragEnter="TilePanel_DragEnter" Drop="TilePanel_Drop" AllowDrop="True" />
</ScrollViewer>

我的自定義面板類:

/// <summary>
/// A Panel Showing Tiles
/// </summary>
public class TilePanel : PermillePanel
{
        public TilePanel()
        {
        }

        protected override Size MeasureOverride(Size constraint)
        {
            //here constraint width or height can be infinite.
            //as tiles are a permille of that height, they too can be infinite after measuring
            //this is unwanted behavior, so we measure in the ArrangeOverride method

            if (constraint.Width == double.PositiveInfinity)
            {
                return new Size(0, constraint.Height);
            }
            else if (constraint.Height == double.PositiveInfinity)
            {
                return new Size(constraint.Width, 0);
            }
            else
            {
                return constraint;
            }
        }

        protected override Size ArrangeOverride(Size arrangeSize)
        {
            //return base.ArrangeOverride(arrangeSize);

            foreach (FrameworkElement child in InternalChildren)
            {
                Size availableSize = new Size();
                //set the width and height for the child
                availableSize.Width = arrangeSize.Width * TilePanel.GetHorizontalPermille(child) / 1000;
                availableSize.Height = arrangeSize.Height * TilePanel.GetVerticalPermille(child) / 1000;

                child.Measure(availableSize);

            }

            // arrange the children on the panel
            // fill lines horizontally, when we reach the end of the current line, continue to the next line

            Size newSize = new Size(arrangeSize.Width, arrangeSize.Height);

            double xlocation = 0;
            double ylocation = 0;

            double ystep = 0;

            double maxYvalue = 0;

            foreach (FrameworkElement child in InternalChildren)
            {
                double endxlocation = xlocation + child.DesiredSize.Width;

                double constrainedWidth = arrangeSize.Width * TilePanel.GetHorizontalPermille(child) / 1000;
                double constrainedHeight = arrangeSize.Height * TilePanel.GetVerticalPermille(child) / 1000;

                if (TilePanel.GetVerticalPermille(child) != 0 && TilePanel.GetHorizontalPermille(child) != 0)
                {
                    //horizontal overflow -> next line
                    if (endxlocation >= this.DesiredSize.Width *1.01)
                    {
                        ylocation += ystep;
                        xlocation = 0;
                    }
                }

                Rect rect = new Rect(xlocation, ylocation, constrainedWidth, constrainedHeight);
                child.Arrange(rect);
                xlocation += constrainedWidth;
                ystep = Math.Max(ystep, constrainedHeight);
                maxYvalue = Math.Max(maxYvalue, ystep + constrainedHeight);
            }

            if (maxYvalue > newSize.Height)
            {
                newSize.Height = maxYvalue;
            }

            return newSize;
        }
    }

ArrangeOverride()調用Measure()會引起問題。 框架會檢測到這一點並強制進行重新測量。 MeasureOverride()設置一個跟蹤點,我敢打賭,即使布局沒有更改1 ,它也會一遍又一遍地被調用。

如果絕對必須從ArrangeOverride()調用Measure() ,則需要有條件地這樣做,以便僅在自上次調用Measure()以來可用大小實際發生變化時才強制重新Measure() 然后,在布局無效時,您將有效地獲得兩次測量+布置遍,而不是一次。 但是,這種方法很不明智,我建議您堅持僅在MeasureOverride()測量的最佳實踐。


1有趣的是,盡管布局中存在明顯的“無限循環”,您的UI仍可能響應輸入。

如果要在ScrollViewer使用自定義Panel則必須添加執行實際滾動的代碼。 您可以通過在自定義Panel實現IScrollInfo接口來實現。

您可以在Tech Pro網站上的WPF教程-實現IScrollInfo頁面中找到說明該界面並提供示例代碼實現的教程 這是一個相當簡單的過程,看起來像這樣:

public void LineDown() { SetVerticalOffset(VerticalOffset + LineSize); }

public void LineUp() { SetVerticalOffset(VerticalOffset - LineSize); }

public void MouseWheelDown() { SetVerticalOffset(VerticalOffset + WheelSize); }

public void MouseWheelUp() { SetVerticalOffset(VerticalOffset - WheelSize); }

public void PageDown() { SetVerticalOffset(VerticalOffset + ViewportHeight); }

public void PageUp() { SetVerticalOffset(VerticalOffset - ViewportHeight); }

...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM