2013年01月15日

[C# WPF]DataGridのスクロール位置を同期する

前回はDataGridの列幅を同期しました。
今回はスクロール位置を同期してみます。

DataGridにはスクロール位置のプロパティはないので
xamlで単純にBindはできません。

今回もソースコードで同期する処理を記述します。

[xaml]

<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<DataGrid x:Name="dataGrid1" ItemsSource="{Binding Items}" AutoGenerateColumns="False" Margin="5">
<DataGrid.Columns>
<DataGridTextColumn Header="Data1" Binding="{Binding Data1}"/>
<DataGridTextColumn Header="Data2" Binding="{Binding Data2}"/>
<DataGridTextColumn Header="Data3" Binding="{Binding Data3}"/>
<DataGridTextColumn Header="Data4" Binding="{Binding Data4}"/>
<DataGridTextColumn Header="Data5" Binding="{Binding Data5}"/>
</DataGrid.Columns>
</DataGrid>
<GridSplitter Grid.Row="1" Height="3" HorizontalAlignment="Stretch" VerticalAlignment="Top"/>
<DataGrid Grid.Row="1" x:Name="dataGrid2" ItemsSource="{Binding Items}" AutoGenerateColumns="False" Margin="5">
<DataGrid.Columns>
<DataGridTextColumn Header="Data1" Binding="{Binding Data1}"/>
<DataGridTextColumn Header="Data2" Binding="{Binding Data2}"/>
<DataGridTextColumn Header="Data3" Binding="{Binding Data3}"/>
<DataGridTextColumn Header="Data4" Binding="{Binding Data4}"/>
<DataGridTextColumn Header="Data5" Binding="{Binding Data5}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>


[ソース]

public partial class MainWindow : Window
{
private DataGridScrollSynchronizer ScrollSync;

private ObservableCollection items = new ObservableCollection();
public ObservableCollection Items { get { return items; } }

public MainWindow()
{
InitializeComponent();

this.DataContext = this;

for (int i = 0; i < 30; i++)
{
var d = new TestClass();
d.Data1 = i * 10 + 1;
d.Data2 = i * 10 + 2;
d.Data3 = i * 10 + 3;
d.Data4 = i * 10 + 4;
d.Data5 = i * 10 + 5;
Items.Add(d);
}
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
ScrollSync = new DataGridScrollSynchronizer(dataGrid1, dataGrid2);
ScrollSync.Direction = SynchronizeDirection.Vertical;
}
}

public class TestClass
{
public int Data1 { get; set; }
public int Data2 { get; set; }
public int Data3 { get; set; }
public int Data4 { get; set; }
public int Data5 { get; set; }

public TestClass()
{
}
}

[Flags]
public enum SynchronizeDirection
{
Horizontal = 0x01,
Vertical = 0x02,
Both = 0x03,
}

public class DataGridScrollSynchronizer
{
private ScrollViewer sv1;
private ScrollViewer sv2;

public SynchronizeDirection Direction { get; set; }

public DataGridScrollSynchronizer(DataGrid dg1, DataGrid dg2)
{
sv1 = GetScrollViewer(dg1);
sv2 = GetScrollViewer(dg2);

sv1.ScrollChanged += sv1_ScrollChanged;
sv2.ScrollChanged += sv2_ScrollChanged;
}

private ScrollViewer GetScrollViewer(FrameworkElement fe)
{
int n = VisualTreeHelper.GetChildrenCount(fe);
for (int i = 0; i < n; i++)
{
var child = VisualTreeHelper.GetChild(fe, i) as FrameworkElement;
if (child == null)
{
continue;
}

if (child is ScrollViewer)
{
return (ScrollViewer)child;
}

var sv = GetScrollViewer(child);
if (sv != null)
{
return sv;
}
}
return null;
}

private void sv1_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (Direction.HasFlag(SynchronizeDirection.Horizontal))
{
sv2.ScrollToHorizontalOffset(sv1.HorizontalOffset);
}
if (Direction.HasFlag(SynchronizeDirection.Vertical))
{
sv2.ScrollToVerticalOffset(sv1.VerticalOffset);
}
}

private void sv2_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (Direction.HasFlag(SynchronizeDirection.Horizontal))
{
sv1.ScrollToHorizontalOffset(sv2.HorizontalOffset);
}
if (Direction.HasFlag(SynchronizeDirection.Vertical))
{
sv1.ScrollToVerticalOffset(sv2.VerticalOffset);
}
}
}


今回は表示するデータクラスを用意しています。
スクロールバーが表示されるように要素数を多めに作成しています。

スクロール位置の同期をする別クラスを作りました。
同期する方向も指定できるようにしています。
同期したいDataGridを指定するだけなので使いまわせると思います。

実行結果です。
1.jpg


posted by cw at 21:00| Comment(2) | TrackBack(0) | Tips | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
同期しないよ〜う
Posted by at 2014年07月09日 01:01
たすかりました!
Posted by at 2017年12月18日 04:26
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

この記事へのトラックバック
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。