Binding warning when scrolling horizontally in datagrid

1.6k views Asked by At

In my WPF application, when I scroll horizontally a DataGrid, Visual Studio 2010 Output print this warning:

System.Windows.Data Error: 5 : Value produced by BindingExpression is not valid for target property.; Value='-0.29487179487171' BindingExpression:Path=CellsPanelHorizontalOffset; DataItem='DataGrid' (Name=''); target element is 'Button' (Name=''); target property is 'Width' (type 'Double')

I'm looking for datagrid template definition; the exception should be caused by the binding on "Button" object:

<Button
       Command="{x:Static DataGrid.SelectAllCommand}"
       Focusable="false"
       Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}"
       Visibility="{Binding Path=HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
       Width="{Binding Path=CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />

Width property is Double, like the CellsPanelHorizontalOffset property in binding.

I can not understand what's wrong, can you help me? Thanks.

2

There are 2 answers

2
Sheridan On BEST ANSWER

The reason for your error is clear from its description:

Value produced by BindingExpression is not valid for target property.;
Value='-0.29487179487171' ...
target element is 'Button'; ...
target property is 'Width'

Therefore, the value that is data bound to the Button.Width is -0.29487179487171, but obviously, a Width cannot be negative. However, if you were to use a Converter there to never pass negative values, you'd simply be hiding the real problem, which is that the CellsPanelHorizontalOffset should never be negative in the first place.

I can only assume that you have used some manual calculation in your customised DataGrid that is returning the wrong value from the DataGridCellsPanel. From the DataGrid Class page on MSDN:

DataGridCellsPanel: Gets the horizontal offset for the DataGridCellsPanel.

1
bbedson On

I had the same problem. It turns out that in my situation the culprit was setting the row header width to zero. The problem is that there is a button in the DG_ScrollViewer whose width is set by determining the width its parent: Button Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=CellsPanelHorizontalOffset}". This will set the width of the button to a negative number, which is not a valid width. I found (for now) that the only way to truly hide the row headers is to set the row header width to zero and then re-write the ScrollViewer template, which will eliminate the error and allow the horizontal scroll to work. This is a good solution if your app-wide data grid design has no row headers, otherwise you may have to set this xaml for different data grids. Hope this helps someone.

<Style BasedOn="{StaticResource ControlBaseStyle}" TargetType="{x:Type DataGrid}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type DataGrid}">
          <Border Padding="{TemplateBinding Padding}"
                  Background="{TemplateBinding Background}"
                  BorderBrush="{TemplateBinding BorderBrush}"
                  BorderThickness="{TemplateBinding BorderThickness}"
                  SnapsToDevicePixels="True"
                  >
            <ScrollViewer Name="DG_ScrollViewer" Focusable="false">
              <ScrollViewer.Template>
                <ControlTemplate TargetType="{x:Type ScrollViewer}">
                  <Grid>
                    <Grid.RowDefinitions>
                      <RowDefinition Height="Auto"/>
                      <RowDefinition Height="*"/>
                      <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                      <ColumnDefinition Width="Auto"/>
                      <ColumnDefinition Width="*"/>
                      <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    *********** hard code the width of this button *********
                    <Button x:Name="HijackThisButton"
                            Width="0"
                            Focusable="false"
                            Visibility="Collapsed"
                            />      
                    <DataGridColumnHeadersPresenter Name="PART_ColumnHeadersPresenter"
                                                    Grid.Column="1"
                                                    Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.Column}}"
                                                    />
                    <ScrollContentPresenter x:Name="PART_ScrollContentPresenter"
                                            Grid.Row="1"
                                            Grid.ColumnSpan="2"
                                            CanContentScroll="{TemplateBinding CanContentScroll}"
                                            />
                    <ScrollBar Name="PART_VerticalScrollBar"
                               Grid.Row="1"
                               Grid.Column="2"
                               Maximum="{TemplateBinding ScrollableHeight}"
                               Orientation="Vertical"
                               ViewportSize="{TemplateBinding ViewportHeight}"
                               Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
                               Value="{Binding Path=VerticalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
                               />
                    <Grid Grid.Row="2" Grid.Column="1">
                      <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=NonFrozenColumnsViewportHorizontalOffset}"/>
                        <ColumnDefinition Width="*"/>
                      </Grid.ColumnDefinitions>
                      <ScrollBar Name="PART_HorizontalScrollBar"
                                 Grid.Column="1"
                                 Maximum="{TemplateBinding ScrollableWidth}"
                                 Orientation="Horizontal"
                                 ViewportSize="{TemplateBinding ViewportWidth}"
                                 Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
                                 Value="{Binding Path=HorizontalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
                                 />
                    </Grid>
                  </Grid>
                </ControlTemplate>
              </ScrollViewer.Template>
              <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
            </ScrollViewer>
          </Border>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
    <Setter Property="VerticalScrollBarVisibility" Value="Auto"/>
  </Style>