WPF開發隨筆收錄-ScrollViewer滑塊太小解決方案

WPF開發隨筆收錄-ScrollViewer滑塊太小解決方案

當ScrollViewer裡面的內容太長時,滾動條的滑塊就會變得很小,然後導致點擊起來不太友好。

最後更新 2022/5/13 上午7:13
流浪g
預計閱讀 4 分鐘
分類
WPF
標籤
.NET WPF

一、前言

在 WPF 開發過程中,ScrollViewer 是一個很常使用到的控制項,在自己工作的專案中,收到一個回饋就是當 ScrollViewer 裡面的內容太長時,捲軸的滑塊就會變得很小,然後導致點擊起來不太友善。一開始想著是透過在樣式裡面設定滑塊的最小值,但都沒法生效。最後換了一個思路來,透過把原有的滑塊隱藏,然後自己加一個控制項來充當滑塊來間接控制 ScrollViewer 的捲動。

二、正文

  1. 這裡就直接拿之前寫的那個曲線圖控制項來進行示範,當曲線圖的資料很多時,滑塊就會顯得很小個,現在是在預設樣式情況下,如果在自訂的樣式情況下會更小

  1. 這裡就直接在曲線圖的頂層放置了一個 Canvas,加入一個 Border 來充當滑塊,注意這裡將整個 Canvas 覆蓋在曲線圖上,因為我還加入了可以直接點擊曲線圖拖曳移動的功能,然後將 ScrollViewer 的滑塊隱藏,設定好滑塊的最小寬度和高度,預設隱藏
<Grid>
    <local:CruveDrawingVisual x:Name="curve" Margin="0,10,0,15" />
    <ScrollViewer
        Name="scroll"
        HorizontalScrollBarVisibility="Hidden"
        ScrollChanged="ScrollViewer_ScrollChanged"
        VerticalScrollBarVisibility="Disabled">
        <Canvas x:Name="canvas" />
    </ScrollViewer>
    <Canvas x:Name="CurvePanel" Background="Transparent">
        <Border
            x:Name="border"
            Canvas.Left="0"
            Canvas.Bottom="0"
            Height="15"
            MinWidth="80"
            Background="Green"
            PreviewMouseLeftButtonDown="Border_PreviewMouseLeftButtonDown"
            Visibility="Collapsed" />
    </Canvas>
</Grid>
  1. 接著再到後台加入對應的邏輯處理程式碼,詳細的一些東西都已經透過備註的形式寫在程式碼裡,這裡就不再囉嗦了
public partial class MainWindow : Window
{
    private bool isAdd = true;
    private List<int> lists = new List<int>();

    private Point point_border;

    private double offset = -1;

    public MainWindow()
    {
        InitializeComponent();

        CurvePanel.MouseMove += delegate (object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                if (Mouse.Captured == null) Mouse.Capture(CurvePanel);

                //拖動滑塊
                if (isBorder)
                {
                    Point point = e.GetPosition(this);
                    //滑鼠超出控制項左邊緣
                    if (point.X - point_border.X <= 0)
                    {
                        scroll.ScrollToHorizontalOffset(0);
                    }
                    //滑鼠超出控制項右邊緣
                    else if (point.X - point_border.X >= CurvePanel.ActualWidth - border.ActualWidth)
                    {
                        scroll.ScrollToHorizontalOffset(lists.Count - CurvePanel.ActualWidth);
                    }
                    //滑鼠在控制項區間
                    else if (point.X - point_border.X > 0 && point.X - point_border.X < CurvePanel.ActualWidth - border.ActualWidth)
                    {
                        double left = point.X - point_border.X;
                        scroll.ScrollToHorizontalOffset((lists.Count - CurvePanel.ActualWidth) / (CurvePanel.ActualWidth - border.ActualWidth) * left);
                    }
                }
                //拖曳畫布
                else
                {
                    if (offset >= 0 && offset <= CurvePanel.ActualWidth)
                    {
                        scroll.ScrollToHorizontalOffset(scroll.HorizontalOffset - (e.GetPosition(this).X - offset));
                    }
                    offset = e.GetPosition(this).X;
                }
            }
            else
            {
                offset = -1;
                isBorder = false;
                Mouse.Capture(null); // 釋放滑鼠捕獲
            }
        };
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        int temp = 20;
        for (int i = 0; i < 24 * 60 * 60 * 2; i++)
        {
            if (isAdd)
            {
                lists.Add(temp);
                temp += 2;
            }
            else
            {
                lists.Add(temp);
                temp -= 2;
            }

            if (temp == 280) isAdd = false;
            if (temp == 20) isAdd = true;
        }
        canvas.Width = lists.Count;
        //判斷是否顯示滑塊
        if (canvas.Width > CurvePanel.ActualWidth)
        {
            border.Visibility = Visibility.Visible;
            //根據ScrollViewer內容的比例計算滑塊的寬度
            border.Width = CurvePanel.ActualWidth * CurvePanel.ActualWidth / canvas.Width;
        }
        else
        {
            border.Visibility = Visibility.Collapsed;
        }
        curve.SetupData(lists);
    }

    private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        curve.OffsetX(scroll.HorizontalOffset);

        Canvas.SetLeft(border, scroll.HorizontalOffset / ((lists.Count - CurvePanel.ActualWidth) / (CurvePanel.ActualWidth - border.ActualWidth)));
    }

    private bool isBorder = false;
    private void Border_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        isBorder = true;
        //取得滑鼠點擊滑塊上的位置
        point_border = e.GetPosition(border);
    }
}
  1. 執行效果如下

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2025/1/26

WPF 藉助自訂 XML 檔案實現國際化

本文詳細介紹了在WPF程式中使用自訂XML檔案實現國際化的方法,包括安裝必備NuGet套件、動態獲取語言清單、動態切換語言、在程式碼和XAML介面中使用翻譯字串等內容,同時提供了原始碼連結,幫助開發者輕鬆實現WPF應用程式的國際化。

繼續閱讀