Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I am using DataGrid to show storagehouse occupancy (Occupied-Show Image With a box, Not Occupied-Show Empty Image).
In DataGrid I am using DataGridTemplateColumn to override the Images.
My Main Form XAML Code:

<xctk:BusyIndicator Name="ctrlBusy" IsBusy="False" BusyContent="Generating Maps..." >
    <Grid>
        <StackPanel>
            <Button Name="btnClick" Grid.Row="0" Click="Button_Click_1" Height="44" VerticalAlignment="Top" 
            HorizontalAlignment="Left" Width="114" Panel.ZIndex="4" Margin="6,3,0,0">Click</Button>

            <StackPanel Orientation="Vertical" Grid.Row="1">
                <TextBlock  Background="SkyBlue" Height="50">

                </TextBlock>
                <DataGrid GridLinesVisibility="None" Background="SkyBlue" 
              BorderBrush="Transparent" IsReadOnly="True" ItemsSource="{Binding}" 
              AutoGenerateColumns="True" AutoGeneratingColumn="dgvMap_AutoGeneratingColumn"   
              CanUserAddRows="False" CanUserSortColumns="true" CanUserDeleteRows="False"  
              HeadersVisibility="Row" Name="dgvMap" SelectionMode="Single" 
              Panel.ZIndex="0" Margin="0,0,0,0" VirtualizingStackPanel.VirtualizationMode="Standard">
                    <!--for removing the blue color bkground default for row selection-->
                    <DataGrid.Resources>
                        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" 
               Color="Transparent"/>
                    </DataGrid.Resources>
                </DataGrid>
                <TextBlock  Background="SkyBlue" Height="50">

                </TextBlock>
            </StackPanel>
        </StackPanel>
    </Grid>
</xctk:BusyIndicator>

Datatemplate for DataGrid:

 <DataTemplate x:Key="MyDataTemplate" DataType="DataRowView">
        <Grid Background="Transparent">
            <Image Tag="{Binding}" Name="Layer0" Margin="0,0,0,0"  Panel.ZIndex="1"  
                   Width="50" Height="50"   ToolTipService.HasDropShadow="True" ToolTipService.ShowDuration="20000" ToolTipService.InitialShowDelay="200" >
                <Image.ToolTip>
                    <StackPanel>
                        <Label FontWeight="Bold" Background="Blue" Foreground="White" Content="{Binding}" />
                        <TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
                            This coil is located in this location. Yard Name is FG. Zone is Dispatch Area.
                        </TextBlock>
                        <Line Stroke="Black" StrokeThickness="1" X2="200" />
                        <StackPanel Orientation="Horizontal">
                            <Label FontWeight="Bold">Report to admin in case of coil location mismatch</Label>
                        </StackPanel>
                    </StackPanel>
                </Image.ToolTip>
                <Image.Resources>
                    <Style TargetType="{x:Type Image}">
                        <Setter Property="Source" Value="{Binding Converter={StaticResource IntToImageConverter}, ConverterParameter = Layer0}" />
                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <!-- Hover image -->
                                <Setter Property="Cursor" Value="Hand"/>
                                <Setter Property="Source" Value="C:\Users\Images\Coil3.png"/>
                                <!--<Setter Property="Source" Value="{Binding  Converter={StaticResource HoverImage}}"/>-->
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Image.Resources>
            </Image>
        </Grid>
    </DataTemplate>

Main Form Code-Behind:

 private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        btnClick.Content = "Data Loaded";
        Stopwatch sw = new Stopwatch();
        DataTable dt = dbLayer.tblSaddleSelectAll();
        sw.Start();
        dgvMap.ItemsSource = dt.DefaultView;
        sw.Stop();
        btnClick.Content = sw.ElapsedMilliseconds.ToString();

    }



  private void dgvMap_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        if (e.PropertyName == "row")
        {
            e.Column.Visibility = System.Windows.Visibility.Hidden;
        }
        var column = new DataRowColumn(e.PropertyName);
        column.Header = e.Column.Header;
        column.CellTemplate = (DataTemplate)Resources["MyDataTemplate"];

        e.Column = column;
    }  

ValueConverter for DataGrid:

public class BoolToImageConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ImageSource result = null;
        var intValue = value.ToString();
        switch (parameter.ToString())
        {
            case "Layer1":
                if (intValue.ToUpper().Contains("EMPTY"))
                {
                    result = null;
                }
                else
                {
                    result = new BitmapImage(new Uri(@"C:\Users\Images\Box3.png"));
                }
                return result;
            default:
                if (intValue.ToUpper().Contains("EMPTY"))
                {
                    //result = null;
                    result = new BitmapImage(new Uri(@"C:\Users\Images\Box1.png"));
                }
                else
                {

                    result = new BitmapImage(new Uri(@"C:\Users\Images\Box2.png"));
                }
                return result;
        }

    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Custom DatagridTemplateColumn:

 public class DataRowColumn : DataGridTemplateColumn
{
    public DataRowColumn(string column) { ColumnName = column; }
    public string ColumnName { get; private set; }
    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        var row = (DataRowView)dataItem;
        var item = row[ColumnName];
        cell.DataContext = item;
        var element = base.GenerateElement(cell, item);
        return element;
    }
}

The Data from Database will be like this:

example of data from database

I will be loading maximum of 250 columns, 20 rows from database.
My questions:

  1. Is datagrid is best way to show map kind of layouts for the data given range? I need to show presence and absence with some tooltip descriptions.
  2. The stopwatch i kept for checking time taken to load DataGrid. It is showing value less than 250ms. But in reality it is taking too much take show and for 4-6 second the UI gets hanged. Why is hanging? How to overcome it? How can i show BusyIndicator till DataGrid is fully created?
  3. Is attaching DataTable's DefaultView to DataGrid is better way to do in performance in wise??
  4. Is there anything(properties) I missed in DataGrid to improve the performance.
share|improve this question
1  
This will never work fine. We are facing a similar issue with a grid (~20 row and ~90 column) and everything is slow as hell becouse Silverlight/desktop WPF application can not handle this kind of situation. I have created an old Windows Forms application to solve our problem and everything becode fast. –  Peter Kiss Jul 20 '13 at 1:08

1 Answer 1

The stopwatch i kept for checking time taken to load DataGrid. It is showing value less than 250ms. But in reality it is taking too much take show and for 4-6 second the UI gets hanged. Why is hanging? How to overcome it?

That's beacuse the datagrid layout update is happening asynchronously. You can work around it by exploiting the dispatcher priority system:

Dispatcher.CurrentDispatcher.BeginInvoke(
                ((Action)(() =>
                {
                    sw.Stop(); //We stop it here, after the datagrid has been rendered
                    btnClick.Content = sw.ElapsedMilliseconds.ToString();
                })),
                DispatcherPriority.Loaded);

The Loaded priority is just below the Render priority, so that code will be executed after the datagrid has been rendered.

How can i show BusyIndicator till DataGrid is fully created?

Use a task to load the data table:

ctrlBusy.IsBusy = true;
var task = Task.Factory.StartNew<DataTable>(() => dbLayer.tblSaddleSelectAll());
task.ContinueWith(
                t => dgvMap.ItemsSource = t.Result.DefaultView, 
                CancellationToken.None, 
                Tasks.TaskContinuationOptions.OnlyOnRanToCompletion, 
                TaskScheduler.FromCurrentSynchronizationContext());

task.ContinueWith(
                t => ctrlBusy.IsBusy = false, 
                CancellationToken.None, 
                Tasks.TaskContinuationOptions.None, 
                TaskScheduler.FromCurrentSynchronizationContext());

I'm sorry i can't help with the other questions.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.