この記事は2019年05月23日に投稿しました。
目次
エッセンシャルWPF:Windows Presentation Foundation (Programmer's SELECTION)
- 作者: Chris Anderson,星睦
- 出版社/メーカー: 翔泳社
- 発売日: 2007/10/31
- メディア: 大型本
- 購入: 6人 クリック: 128回
- この商品を含むブログ (32件) を見る
1. はじめに
こんにちは、iOSのエディタアプリPWEditorの開発者の二俣です。
今回は業務で使用しているWPFで複数のDataGridを同期してスクロールする方法についてです。
2. WPFで複数のDataGridを同期してスクロールする
WPFで複数のDataGridを同期してスクロールする方法ですが、次のサイトを参考にさせていただきました。
参考にしたサイトでは、対象となるDataGridは2つのみです。
それを複数のDataGridでも同期してスクロールするようにしました。
実葬例
MainWindow.xaml
<Window x:Class="WPFDataGridSync.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WPFDataGridSync" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" ContentRendered="Window_ContentRendered"> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <DataGrid Grid.Row="0" Name="dataGrid1" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible"/> <DataGrid Grid.Row="1" Name="dataGrid2" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible"/> <DataGrid Grid.Row="2" Name="dataGrid3" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible"/> </Grid> </Window>
MainWindow.xaml.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace WPFDataGridSync { class SampleData { public string Data1 { get; set; } public string Data2 { get; set; } public string Data3 { get; set; } public string Data4 { get; set; } public string Data5 { get; set; } } /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { //! スクロール同期処理 private DataGridScrollSynchronizer ScrollSynchronizer; /** * @brief コンストラクタ */ public MainWindow() { InitializeComponent(); // 各データグリッドにテストデータを設定します。 var list = new List<SampleData>(); for (int i = 0; i < 10; ++i) { var sampleData = new SampleData() { Data1 = $"Data{i}-0", Data2 = $"Data{i}-1", Data3 = $"Data{i}-2", Data4 = $"Data{i}-3", Data5 = $"Data{i}-4", }; list.Add(sampleData); } dataGrid1.ItemsSource = list; dataGrid2.ItemsSource = list; dataGrid3.ItemsSource = list; } /** * @brief ウィンドウが表示された後に呼び出されます。 * * @param [in] sender ウィンドウ * @param [in] e イベント */ private void Window_ContentRendered(object sender, EventArgs e) { // データグリッドのスクロール同期を設定します。 var dataGridList = new List<DataGrid>(); dataGridList.Add(dataGrid1); dataGridList.Add(dataGrid2); dataGridList.Add(dataGrid3); ScrollSynchronizer = new DataGridScrollSynchronizer(dataGridList, SynchronizeDirection.Both); } } }
DataGridScrollSynchronizer.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace WPFDataGridSync { /** * @brief スクロールの同期する方向 */ [Flags] public enum SynchronizeDirection { //! 水平方向 Horizontal = 0x01, //! 垂直方向 Vertical = 0x02, //! 両方 Both = 0x03, } /** * @brief データグリッドスクロール同期クラス */ public class DataGridScrollSynchronizer { //! スクロールビューワーリスト private List<ScrollViewer> ScrollViewerList; //! スクロール方向 private SynchronizeDirection Direction { get; set; } /** * @brier コンストラクタ * * @param [in] dataGridList 同期するデータグリッドリスト * @param [in] direction 同期するスクロール方向 */ public DataGridScrollSynchronizer(List<DataGrid> dataGridList, SynchronizeDirection direction = SynchronizeDirection.Both) { ScrollViewerList = new List<ScrollViewer>(); // データグリッド数を取得します。 int dataGridNum = dataGridList.Count; // 同期するデータグリッド数が1以下の場合、何もしない。 if (dataGridNum < 2) { return; } // データグリッド数分繰り返します。 for (int i = 0; i < dataGridNum; ++i) { // データグリッドのスクロールビューワーを取得します。 var dataGrid = dataGridList[i]; var scrollViewer = GetScrollViewer(dataGrid); // スクロールビューワーにイベントハンドラを設定します。 scrollViewer.ScrollChanged += ScrollChanged; // スクロールビューワーを識別するためタグを設定します。 scrollViewer.Tag = i; // スクロールビューワーリストに保存します。 ScrollViewerList.Add(scrollViewer); } // スクロール方向を保存します。 Direction = direction; } /** * @brief スクロールビューワーを取得します。 * * @param [in] element エレメント * @return スクロールビューワー * 取得できない場合、nullを返却します。 */ private ScrollViewer GetScrollViewer(FrameworkElement element) { // 引数elementのビジュアルオブジェクト数分繰り返す。 var childrenNum = VisualTreeHelper.GetChildrenCount(element); for (int i = 0; i < childrenNum; ++i) { // ビジュアルオブジェクトを取得します。 var child = VisualTreeHelper.GetChild(element, i) as FrameworkElement; // ビジュアルオブジェクトが取得できない場合 if (child == null) { // 次を取得します。 continue; } // 取得したビジュアルオブジェクトがスクロールビューワーの場合 if (child is ScrollViewer) { // 取得したスクロールビューワーを返却します。 return child as ScrollViewer; } // 次のビジュアルオブジェクトを取得します。 child = GetScrollViewer(child); if (child != null) { return child as ScrollViewer; } } return null; } /** * @brief スクロールされた時に呼び出されるます。 * * @param [in] sender スクロールビューワー * @param [in] e スクロールチェンジイベント */ private void ScrollChanged(object sender, ScrollChangedEventArgs e) { var srcScrollViewer = sender as ScrollViewer; // 同期するスクロール方向が水平方向の場合 if (Direction.HasFlag(SynchronizeDirection.Horizontal)) { // スクロールするオフセットを取得します。 var offset = srcScrollViewer.HorizontalOffset; // スクロールビューワー数分繰り返します。 foreach (var dstScrollVierwer in ScrollViewerList) { // スクロールしたスクロールビューワーは無視します。 if (dstScrollVierwer.Tag == srcScrollViewer.Tag) { continue; } // 同期するスクロールビューワーをスクロールします。 dstScrollVierwer.ScrollToHorizontalOffset(offset); } } // 同期するスクロール方向が垂直方向の場合 if (Direction.HasFlag(SynchronizeDirection.Vertical)) { // スクロールするオフセットを取得します。 var offset = srcScrollViewer.VerticalOffset; // スクロールビューワー数分繰り返します。 foreach (var dstScrollVierwer in ScrollViewerList) { // スクロールしたスクロールビューワーは無視します。 if (dstScrollVierwer.Tag == srcScrollViewer.Tag) { continue; } // 同期するスクロールビューワーをスクロールします。 dstScrollVierwer.ScrollToVerticalOffset(offset); } } } } }
3. おわりに
今作成中のアプリで、6~23時までの時間ごとのカラムを持つ複数のDataGridを表示させています。
カラム数が多いため、画面サイズによって横スクロールすることになります。
その場合、全てのDataGridのカラム位置を同期させる必要があり、今回の対応を調査しました。
実戦で役立つ C#プログラミングのイディオム/定石&パターン
- 作者: 出井秀行
- 出版社/メーカー: 技術評論社
- 発売日: 2017/02/18
- メディア: 大型本
- この商品を含むブログ (1件) を見る
紹介している一部の記事のコードはGitlabで公開しています。
興味のある方は覗いてみてください。
私が勤務しているニューラルでは、主に組み込み系ソフトの開発を行っております。
弊社製品のハイブリッドOS Bi-OSは高い技術力を評価されており、特に制御系や通信系を得意としています。
私自身はiOSモバイルアプリやウィンドウズアプリを得意としております。
ソフトウェア開発に関して相談などございましたら、お気軽にご連絡ください。
また一緒に働きたい技術者の方も随時募集中です。
興味がありましたらご連絡ください。
EMAIL : info-nr@newral.co.jp / m-futamata@newral.co.jp
TEL : 042-523-3663
FAX : 042-540-1688