質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.75%

  • C#

    6565questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • WPF

    656questions

    Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

  • XAML

    240questions

    XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。

二つのListView スクロールを同期したい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 241

 前提・実現したいこと

Grid内にListViewを二つ並べ、ListViewにスクロールが表示されるまでListView.ItemsにTextBlockを追加しました。
このListView二つのスクロールを、同時に動かしたいです。

 発生している問題・エラーメッセージ

エラーメッセージは特になし
左のListViewのスクロールを動かせば右のListViewのスクロールが同時に動くようにし、
右も同様の動きをさせたい
Teratailの、質問投稿画面の文章を打ち込む部分と、右のプレビュー画面みたいな感じです。

 該当のソースコード

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="300" Width="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ListView Grid.Column="0">
            <ListView.Items>
                <TextBlock Text="a"/>
                <TextBlock Text="b"/>
                <TextBlock Text="c"/>
                <TextBlock Text="d"/>
                <TextBlock Text="e"/>
                <TextBlock Text="f"/>
                <TextBlock Text="g"/>
                <TextBlock Text="h"/>
                <TextBlock Text="i"/>
                <TextBlock Text="j"/>
                <TextBlock Text="k"/>
                <TextBlock Text="l"/>
                <TextBlock Text="m"/>
                <TextBlock Text="n"/>
                <TextBlock Text="o"/>
                <TextBlock Text="p"/>
                <TextBlock Text="q"/>
                <TextBlock Text="r"/>
                <TextBlock Text="s"/>
                <TextBlock Text="t"/>
                <TextBlock Text="u"/>
                <TextBlock Text="v"/>
                <TextBlock Text="w"/>
                <TextBlock Text="x"/>
                <TextBlock Text="y"/>
                <TextBlock Text="z"/>
            </ListView.Items>
        </ListView>
        <ListView Grid.Column="1">
            <ListView.Template>
                <ControlTemplate>
                    <ItemsPresenter/>
                </ControlTemplate>
            </ListView.Template>
            <ListView.Items>
                <TextBlock Text="a"/>
                <TextBlock Text="b"/>
                <TextBlock Text="c"/>
                <TextBlock Text="d"/>
                <TextBlock Text="e"/>
                <TextBlock Text="f"/>
                <TextBlock Text="g"/>
                <TextBlock Text="h"/>
                <TextBlock Text="i"/>
                <TextBlock Text="j"/>
                <TextBlock Text="k"/>
                <TextBlock Text="l"/>
                <TextBlock Text="m"/>
                <TextBlock Text="n"/>
                <TextBlock Text="o"/>
                <TextBlock Text="p"/>
                <TextBlock Text="q"/>
                <TextBlock Text="r"/>
                <TextBlock Text="s"/>
                <TextBlock Text="t"/>
                <TextBlock Text="u"/>
                <TextBlock Text="v"/>
                <TextBlock Text="w"/>
                <TextBlock Text="x"/>
                <TextBlock Text="y"/>
                <TextBlock Text="z"/>
            </ListView.Items>
        </ListView>
    </Grid>
</Window>

 試したこと

見たサイト
[WPF] 複数のListViewのスクロールバーを同期させたい。
→ズバリこれと思いましたが、ビヘイビアというものの書き方が分からなかった。
→コードビハインドで書こうと思ったが、スクロールのイベントを取得する方法が分からなかった。
→Themes:ListBoxChromeが分からなかった。
→回答の「ListViewのScrollViewerを無くして、ListViewをScrollViewerを囲む」というのも検討したが、
<listView>の中に

    <ListView.Template>
        <ControlTemplate>
            <ItemsPresenter/>
        </ControlTemplate>
    </ListView.Template>

を書いてみたが何も起きなかった。

WPFのScrollViewerやScrollBarのスクロール位置を同期させる
→ScrollViewerでのやり方だったので分からなかった。
→「ListViewとかを使えよ」という文がありますが、これは「ScrollViewerはスクロールの同期が難しいが、ListViewなら簡単に出来る」という意図なのか?

 補足情報(FW/ツールのバージョンなど)

  • .NET Framework 4.5.1

参考にできるサイトでも構いませんので、皆さんの力をお借り出来ればと思います。
どうぞよろしくお願いいたします。

 現在のソースコード

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="300" Width="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <!--右のスクロールを動かす→左のスクロールが同期する、という動作は未実装です。-->
        <!--現在、仮にMouseUpイベントを拾っていますが、これでよいのでしょうか?-->
        <!--ほぼほぼ想定通りの動きをするのですが、どれかItemsをクリックしないと反応してくれないのが心残り…-->
        <ListView Name="LeftListView" Grid.Column="0" MouseUp="LeftListView_MouseUp">
            <ListView.Items>
                <TextBlock Text="a"/>
                <TextBlock Text="b"/>
                <TextBlock Text="c"/>
                <TextBlock Text="d"/>
                <TextBlock Text="e"/>
                <TextBlock Text="f"/>
                <TextBlock Text="g"/>
                <TextBlock Text="h"/>
                <TextBlock Text="i"/>
                <TextBlock Text="j"/>
                <TextBlock Text="k"/>
                <TextBlock Text="l"/>
                <TextBlock Text="m"/>
                <TextBlock Text="n"/>
                <TextBlock Text="o"/>
                <TextBlock Text="p"/>
                <TextBlock Text="q"/>
                <TextBlock Text="r"/>
                <TextBlock Text="s"/>
                <TextBlock Text="t"/>
                <TextBlock Text="u"/>
                <TextBlock Text="v"/>
                <TextBlock Text="w"/>
                <TextBlock Text="x"/>
                <TextBlock Text="y"/>
                <TextBlock Text="z"/>
            </ListView.Items>
        </ListView>
        <ListView Name="RightListView" Grid.Column="1">
            <ListView.Items>
                <TextBlock Text="a"/>
                <TextBlock Text="b"/>
                <TextBlock Text="c"/>
                <TextBlock Text="d"/>
                <TextBlock Text="e"/>
                <TextBlock Text="f"/>
                <TextBlock Text="g"/>
                <TextBlock Text="h"/>
                <TextBlock Text="i"/>
                <TextBlock Text="j"/>
                <TextBlock Text="k"/>
                <TextBlock Text="l"/>
                <TextBlock Text="m"/>
                <TextBlock Text="n"/>
                <TextBlock Text="o"/>
                <TextBlock Text="p"/>
                <TextBlock Text="q"/>
                <TextBlock Text="r"/>
                <TextBlock Text="s"/>
                <TextBlock Text="t"/>
                <TextBlock Text="u"/>
                <TextBlock Text="v"/>
                <TextBlock Text="w"/>
                <TextBlock Text="x"/>
                <TextBlock Text="y"/>
                <TextBlock Text="z"/>
            </ListView.Items>
        </ListView>
    </Grid>
</Window>
// MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using System.Windows.Controls;
using System.Windows.Media;

namespace WpfApplication1
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void LeftListView_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            var left = LeftListView;
            var scroll = left.Descendants<ScrollViewer>().FirstOrDefault();

            scroll.ScrollChanged += scroll_ScrollChanged;
        }

        private void scroll_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            var right = RightListView;
            var scroll = right.Descendants<ScrollViewer>().FirstOrDefault();

            double scrollValue = e.VerticalOffset;
            scroll.ScrollToVerticalOffset(scrollValue);
        }
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

ScrollViewer は ListBox のビジュアルツリーの中に隠れています。
参考: VisualTreeの子孫要素を取得する

VisualTreeHelper を使って ScrollViewer を取得してください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/12 11:40

    コメントありがとうございます。返信が遅くなってしまい申し訳ございません。もう少し質問してもよろしいでしょうか。
    ①「ListBoxのビジュアルツリーの中に」とありますが、「ListViewのビジュアルツリーの中に」と読み替えて問題ないでしょうか? それとも私が勘違いしているのでしょうか?
    ②ListViewをスクロールした時のイベントを取得するにはどうすればいいのでしょうか?
    ご返信いただければ幸いです。どうぞよろしくお願いいたします。

    キャンセル

  • 2018/06/12 13:04

    ①すみません私の間違いです。読み替えて下さい。
    ②なぜ ScrollViewer 取得させようとしたかというと、ScrollViewer に ScrollChanged イベントや 水平垂直方向のオフセット情報があるからです。

    キャンセル

  • 2018/06/12 15:52

    返信ありがとうございます。
    私の理解が足らず、お手数をおかけし申し訳ないのですが、②についてもう少し質問よろしいでしょうか。
    ListViewからScrollViewerを取得したり、ScrollChangedイベントの発火など、
    ほぼほぼ想定通りに動くことは確認したのですが、
    ListViewのイベントを拾い、コードビハインドで書いているのですが、
    ListViewの何のイベントを発生させたらよいのでしょうか?
    現在、仮としてMouseUpイベントを拾っているのですが、
    これでよいのでしょうか? もっと適切なイベントはありますか?
    (意図通り伝わっているか不安なので質問欄に現在のコードを記載しました。ご確認いただければ幸いです。)

    キャンセル

  • 2018/06/12 18:21

    スマホなのでコードかけなくてすみません。
    面倒なので一部略語で書きます。

    1. MainWindow.ContentRendered イベント ハンドラを xaml に追加。
    2. 上記ハンドラ内で LV からそれぞれ SV を取得 & プライベートフィールドに格納。
    さらに各 SV に ScrollChanged ハンドラを設定。
    3. SV1 のイベントハンドラで SV2 にオフセット設定。 SV2 のハンドラはその逆。


    添字を付けたいだけなら VM をちょっと改造して、DataTemplate を使うほうがいいですね。確かそんな過去の質問にあった様な。。。

    キャンセル

  • 2018/06/13 13:51

    理想通りの動作まで仕上げることが出来ました。この度は誠にありがとうございました!

    添字につきましては、また別の質問に挙げるかもしれません。
    その時はよろしくお願いいたします。

    キャンセル

0

InitializeComponent();直後だとまだScrollViewerが存在していないので駄目ですね。。。

MouseUpでは一度クリックしないといけませんが、MouseMoveであればクリックせずとも発火させられます。
ただ、毎回MouseMoveのたびにイベントを追加してしまうと、1度のMouseMoveで大量のscroll_ScrollChangedがコールされてしまうので、一度だけ登録するような仕組みが理想です。

適当に考えたもの:

        private ScrollViewer lastLeftScrollView;

        private void LeftListView_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            var scroll = LeftListView.Descendants<ScrollViewer>().FirstOrDefault();
            if (scroll != null)
            {
                if (!Object.ReferenceEquals(lastLeftScrollView, scroll))
                {
                    lastLeftScrollView = scroll;
                    scroll.ScrollChanged += scroll_ScrollChanged;
                }
            }
        }

本題とは逸れますが、2つのリストビューを並べて同期させるよりは、一つのリストビューに、見た目2列分のアイテムを配置した方が実装しやすいのではないかと思いました。
(諸事情によりそういった案は却下されたのだと思いますが(^_^;))

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/12 17:52

    コメントありがとうございます。
    お察しの通り、MouseUpだとクリックしないと発火されないのが悩みでした。
    MouseMoveで1度だけ呼び出せばよかったのですね。ありがとうございます。

    一つのリストビューに…という話ですが、元々はそう実装してほしかったです…。
    ListViewにNo.表示が欲しくて作ってもらったら、
    「何かGridの中にListViewが並んでるんですけど…一緒に動いてくれないんですけど…」
    となって、今回の質問に踏み切りました。
    今になってListViewに連番を振りたいという質問をした方が楽だったのかなとか思い始めました…。

    キャンセル

  • 2018/06/13 13:52 編集

    理想通りの動作まで仕上げることが出来ました。この度は誠にありがとうございました!

    ListView内に見た目2列文のアイテム、につきましては、また別の質問に挙げるかもしれません。
    その時はよろしくお願いいたします。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.75%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C#

    6565questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • WPF

    656questions

    Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

  • XAML

    240questions

    XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。