views:

19

answers:

0

I have written a custom control MyControl with virtual content that is much wider than the control itself, and I want to make use of the ScrollBar-control to scroll the virtual content of my own control. My control has 3 properties, that are important in this scenario:

  • Width: the physical width of the control
  • VirtualWidth: the width of the virtual content of the control, VirtualWidth >= Width
  • VirtualOffset: the offset from the left border of the virtual content to the left border of the rendered content of the control

The virtual content is drawn in my custom control depending on the VirtualOffset, which is bound to the Value of a ScrollBar. Using the ScrollBar, I have now set Minimum to 0, Maximum to VirtualWidth and ViewportSize to Width, like follows:

<ScrollBar Name="scrollBar1"
  Minimum="0"
  Maximum="{Binding ElementName=myControl, Path=VirtualWidth}"
  ViewportSize="{Binding ElementName=myControl, Path=ActualWidth}"/>

<mns:MyControl Name="myControl"
  VirtualOffset="{Binding ElementName=scrollBar1, Path=Value}"/>

Now here comes the problem:

When setting the ScrollBar.Maximum to the MyControl.VirtualWidth (which happens through the binding), I can actually scroll over my content to the right, which means I can scroll as much further than I should be allowed, as my control is wide. The solution would be to set the ScrollBar.Maximum value to MyControl.VirtualWidth-MyControl.Width like in the following sample, which isn't possible in XAML:

<ScrollBar Name="scrollBar1"
  Minimum="0"
  Maximum="{Binding ElementName=myControl, Path=VirtualWidth} - {Binding ElementName=myControl, Path=Width}"
  ViewportSize="{Binding ElementName=myControl, Path=ActualWidth}"/>

Non-working solutions I have already tried:

1. ScrollViewer

With ScrollViewer and a non-virtual MyControl it works as it should, except that WPF has problems with drawing geometry at very high coordinates, and also this solution isn't very efficient.

2. XAML Transforms

With an addition it would work like explained in this posting, but I need a subtraction and ScaleTransform doesn't support negative numbers, otherwise I could have done the following:

[...]
  <TransformGroup>
    <TranslateTransform X="{Binding ElementName=myControl, Path=VirtualWidth}"/>
    <TransformGroup>
      <TranslateTransform X="{Binding ElementName=myControl, Path=Width}"/>
      <ScaleTransform ScaleX="-1" />
    </TransformGroup>
  </TransformGroup>
[...]
<ScrollBar Name="scrollBar1"
  Minimum="0"
  Maximum="{Binding ElementName=theTransformElementAbove, Path=RenderTransform.Value.OffsetX}"
  ViewportSize="{Binding ElementName=myControl, Path=ActualWidth}"/>

3. IValueConverter

This approach doesn't work because the ConverterParameter-property doesn't support bindings, otherwise I could have bound the MyControl.Width to the parameter and calculated the subtration inside the converter.

Does anyone have any other ideas how to solve this problem? The only thing I can still think of is a dirty hack, by introducing an additional property in my control that returns VirtualWidth-Width, but if there is any way to avoid this I'd be very happy.