WPF開発エッセイ集-ScrollViewerスライダが小さすぎるソリューション

WPF開発エッセイ集-ScrollViewerスライダが小さすぎるソリューション

ScrollViewerのコンテンツが長すぎると、スクロールバーのスライダーが小さくなり、クリックしにくくなります。

最后更新 2022/05/13 7:13
流浪g
预计阅读 3 分钟
分类
WPF
标签
.NET WPF

I.序文

WPF開発プロセスでは、ScrollViewerは非常に頻繁に使用されるコントロールであり、自分のプロジェクトでは、ScrollViewer内のコンテンツが長すぎると、スクロールバーのスライダーが小さくなり、クリックしにくくなるというフィードバックを受けました。最初はスタイル内にスライダーの最小値を設定することを考えましたが、うまくいきませんでした。最後に、元のスライダーを非表示にし、スライダーとして機能するコントロールを追加してScrollViewerのスクロールを間接的に制御するという考え方を変えました。

2.本文

  1. ここでは、前に書いたグラフコントロールを直接デモンストレーションするために、グラフのデータが多い場合、スライダーは非常に小さく見えますが、今はデフォルトのスタイルで、カスタムスタイルの場合は非常に小さくなります。

  1. ここでは、グラフの最上位に直接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. 動作効果は以下の通り

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 2025/09/13

WPFからAvaloniaへの移行シリーズ:WPFプログラムをAvaloniaに移行する必要がある理由

ここ数年、当社のホストソフトウェアは主にWPFとWin Formで開発されてきました。これらのテクノロジーはWindowsプラットフォームで非常にうまく機能し、小規模なパイロット生産から今日の大規模なデリバリまでの段階を経てきました。しかし、ビジネスの成長と顧客のニーズの変化に伴い、単一のWindowsテクノロジースタックは私たちが乗り越えなければならないハードルになりました。

继续阅读
同分类 / 同标签 2025/01/26

WPFはカスタムXMLファイルで国際化を実現

この記事では、必要なNuGetパッケージのインストール、言語リストの動的取得、言語の動的切り替え、コードとxamlインターフェイスでの翻訳文字列の使用、開発者がWPFアプリケーションを簡単に国際化できるようにするソースコードへのリンクなど、WPFプログラムでカスタムXMLファイルを使用した国際化の方法について詳しく説明します。

继续阅读