Pages

Thursday, August 30, 2012

WP7: alternative of DataGrid with fixed header and other panels


I had a problem in my project on Windows Phone 7. I need to do big area with 24 rows and some count columns. The most important thing is that my header and first left column must be fixed.
After searching I didn't find any standart controls like DataGrid or DataGridView in Silverlight or in WPF.
My decision is simple. I did Grid with four cells and did synchronization between scrollviewers.
See xaml code:
<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
 
        <Border Grid.Row="0" Grid.Column="0" 
                BorderThickness="1" BorderBrush="White" Background="Gray"/>
 
        <ScrollViewer x:Name="headerScv" Grid.Row="0" Grid.Column="1"
                      BorderThickness="1" BorderBrush="White" Background="Gray"
                      VerticalScrollBarVisibility="Visible" 
                      HorizontalScrollBarVisibility="Visible"
                      ManipulationMode="Control" MouseEnter="scroller_MouseEnter"
                      ManipulationCompleted="scrollviewer_ManipulationCompleted">
            <Grid x:Name="headerGrid" Height="100" Width="1000" ShowGridLines="False" >
                <Grid.Background>
                    <RadialGradientBrush>
                        <GradientStop Color="#FF5F1010" Offset="0"/>
                        <GradientStop Color="#FF822E2E" Offset="0.344"/>
                        <GradientStop Color="#FFC58C8C" Offset="1"/>
                    </RadialGradientBrush>
                </Grid.Background>
            </Grid>
        </ScrollViewer>
 
        <ScrollViewer x:Name="leftSideScv" Grid.Row="1" Grid.Column="0"
                    BorderThickness="1" BorderBrush="White" Background="Gray"
                    VerticalScrollBarVisibility="Visible"
                    HorizontalScrollBarVisibility="Visible"
                    ManipulationMode="Control" MouseEnter="scroller_MouseEnter" 
                    ManipulationCompleted="scrollviewer_ManipulationCompleted">
            <Grid Width="100" Height="1000" ShowGridLines="False">
                <Grid.Background>
                    <RadialGradientBrush>
                        <GradientStop Color="Black" Offset="0"/>
                        <GradientStop Color="#FFD42929" Offset="1"/>
                    </RadialGradientBrush>
                </Grid.Background>
            </Grid>
        </ScrollViewer>
 
        <ScrollViewer x:Name="centerScv" Grid.Row="1" Grid.Column="1" 
                      BorderThickness="1" BorderBrush="White" Background="Gray"
                      VerticalScrollBarVisibility="Visible" 
                      HorizontalScrollBarVisibility="Visible"
                      ManipulationMode="Control" MouseEnter="scroller_MouseEnter"
                      ManipulationCompleted="scrollviewer_ManipulationCompleted">
            <Grid x:Name="meetingsGrid" ShowGridLines="False" Width="1000" Height="1000">
                <Grid.Background>
                    <RadialGradientBrush>
                        <GradientStop Color="Black" Offset="0"/>
                        <GradientStop Color="#FF2D9924" Offset="1"/>
                    </RadialGradientBrush>
                </Grid.Background>
            </Grid>
        </ScrollViewer>
 
    </Grid>
See code behind:
public partial class MainPage : PhoneApplicationPage
    {
        #region Init
        public MainPage()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(MainPage_Loaded); 
        }
        #endregion
 
        #region For sync scrollers
        ScrollViewer masterScroller;
 
        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            ScrollBar vHeaderScvBar1, hHeaderScvBar1, vleftSideScvBar2, 
                hleftSideScvBar2, vCenterScvBar3, hCenterScvBar3;
            vHeaderScvBar1 = ((FrameworkElement)VisualTreeHelper.GetChild(headerScv, 0))
                .FindName("VerticalScrollBar") as ScrollBar;
            vHeaderScvBar1.ValueChanged += vHeaderScvBar1_ValueChangedHandler;
            hHeaderScvBar1 = ((FrameworkElement)VisualTreeHelper.GetChild(headerScv, 0))
                .FindName("HorizontalScrollBar") as ScrollBar;
            hHeaderScvBar1.ValueChanged += hHeaderScvBar1_ValueChangedHandler;
 
            vleftSideScvBar2 = ((FrameworkElement)VisualTreeHelper.GetChild(leftSideScv, 0))
                .FindName("VerticalScrollBar") as ScrollBar;
            vleftSideScvBar2.ValueChanged += vleftSideScvBar2_ValueChangedHandler;
            hleftSideScvBar2 = ((FrameworkElement)VisualTreeHelper.GetChild(headerScv, 0))
                .FindName("HorizontalScrollBar") as ScrollBar;
            hleftSideScvBar2.ValueChanged += hleftSideScvBar2_ValueChangedHandler;
 
            vCenterScvBar3 = ((FrameworkElement)VisualTreeHelper.GetChild(centerScv, 0))
                .FindName("VerticalScrollBar") as ScrollBar;
            vCenterScvBar3.ValueChanged += vCenterSideScvBar3_ValueChangedHandler;
            hCenterScvBar3 = ((FrameworkElement)VisualTreeHelper.GetChild(centerScv, 0))
                .FindName("HorizontalScrollBar") as ScrollBar;
            hCenterScvBar3.ValueChanged += hCenterSideScvBar3_ValueChangedHandler;
        }
 
        private void scroller_MouseEnter(object sender, MouseEventArgs e)
        {
 
        }
 
        private void scrollviewer_ManipulationCompleted(object sender,
            ManipulationCompletedEventArgs e)
        {
            masterScroller = sender as ScrollViewer;
        }
 
        void hHeaderScvBar1_ValueChangedHandler(object sender, 
            RoutedPropertyChangedEventArgs<double> e)
        {
            if (masterScroller == headerScv)
                centerScv.ScrollToHorizontalOffset(e.NewValue);
        }
 
        void vHeaderScvBar1_ValueChangedHandler(object sender, 
            RoutedPropertyChangedEventArgs<double> e)
        {
            if (masterScroller == headerScv)
                centerScv.ScrollToVerticalOffset(e.NewValue);
        }
 
        void vleftSideScvBar2_ValueChangedHandler(object sender, 
            RoutedPropertyChangedEventArgs<double> e)
        {
            if (masterScroller == leftSideScv)
                centerScv.ScrollToVerticalOffset(e.NewValue);
        }
 
        void hleftSideScvBar2_ValueChangedHandler(object sender, 
            RoutedPropertyChangedEventArgs<double> e)
        {
            if (masterScroller == leftSideScv)
                centerScv.ScrollToHorizontalOffset(e.NewValue);
        }
 
        void hCenterSideScvBar3_ValueChangedHandler(object sender, 
            RoutedPropertyChangedEventArgs<double> e)
        {
            if (masterScroller == centerScv)
            {
                headerScv.ScrollToHorizontalOffset(e.NewValue);
            }
        }
 
        void vCenterSideScvBar3_ValueChangedHandler(object sender, 
            RoutedPropertyChangedEventArgs<double> e)
        {
            if (masterScroller == centerScv)
            {
                leftSideScv.ScrollToVerticalOffset(e.NewValue);
            }
        }
        #endregion
    }