데이터 바인딩 8

2개의 DataGrid를 만들고 스크롤 위치를 동기화 시켜 보자.

DataGrid에는 스크롤 위치의 속성이 없기 때문에 xaml만으로 할 수는 없다.
소스로 동기화 처리를 해야 한다.

<Window x:Class="BindingDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="BindingDemo" Height="351" Width="297" DataContext="{Binding}" Loaded="Window_Loaded">
    <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>
</Window>

 

using System.Collections.ObjectModel;

namespace BindingDemo
{
    public partial class MainWindow : Window
    {
        private DataGridScrollSynchronizer ScrollSync;

        private ObservableCollection<TestClass> items = new ObservableCollection<TestClass>();
        public ObservableCollection<TestClass> 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);
            }
        }
    }
}

스크롤 위치 동기화를 위해 DataGridScrollSynchronizer 클래스를 만든다.
생성자에서 2개의 DataGrid를 지정 한다.
이 클래스는 스크롤의 동기화 방향을 지정 할 수 있다.


다운로드 : DataGridScrollSynchronizer.zip

 

참고)  http://cswpf.seesaa.net/index-11.html