WPF : cvb.display and zoom

#1

Hi !
I have many problem with cvb.display in WPF and zoom.
This is an exemple of code but in my application when I zoom, it is always center in the center of the picture …
Have you an exemple that work ?
Thanks

CVB_TEST_ZOOM.zip (10.1 KB)

#2

Hi @algoptic,

the program you attached (btw: please delete the bin and obj folders prior to uploading) makes use of the zoom adorner, a little built-in widget in the bottom right corner of the display that allows manipulating the ZoomFactor property of the Stemmer.Cvb.Wpf.Controls.Display object:
image
However, there are two aspects to zooming - the zoom factor and the zoom center. As the zoom adorner only manipulates the zoom factor, but not the zoom center it always invariably zooms right into the middle of the image.

There are two ways around this:

  1. Use Mouse Zoom & Pan
    When holding down the CTRL key you can change the zoom factor with the mouse wheel. While doing so, the zoom center will be nudged towards the pixel above which your mouse cursor is hovering while you rotate the wheel. You may also (while holding the CTRL key) pan (click & hold left mouse button on a pixel in the display and move the mouse) - this will change the zoom center but not the zoom factor (the same effect as with panning may also be achieved using the scrollbars at the right and bottom edge of the Stemmer.Cvb.Wpf.Controls.Display control).
  2. Add Logic to Modify the ZoomCenter
    ZoomCenter is a property of the Stemmer.Cvb.Wpf.Controls.Display control that you can affect programmatically. Unfortunately, as it is a structured value type property you cannot do it directly in a simply two way binding. I have therefore modified your code slightly to include two sliders that allow you to change the ZoomCenter in code-behind (code-behind is arguably not the most beautiful solution - a view model approach would have been nicer but to keep my changes simple I opted for code-behind). I took the liberty to add some layout code to your xaml Files for those changes.

One thing to point out about the ZoomCenter property is that it behaves similar to a control’s Width and Height property. When you set a control’s Width and/or Height it is not guaranteed that the control will be rendered using the values you have set - those values are only taken as an input to the underlying layout system which might choose to overrule your “recommendations” as it sees fit. For that reason, WPF controls also have the properties ActualWidth and ActualHeight - these reflect what the layout system ended up using.

With the Stemmer.Cvb.Wpf.Controls.Display.ZoomCenter the behavior is similar: You can use it to point out where you would like to have it, but the control may overrule it and use what is stored in the ActualZoomCenter property. To illustrate the difference in your code sample I have added two text blocks to the form that bind (one-way) to the ActualZoomCenter.

CVB_TEST_ZOOM_Modified.zip (10.4 KB)

Two more comments:

  • I noticed that in your application the AnyCPU configuration had the Prefer 32 Bit box ticked. This is a bit dangerous because on an x64 installation of 64 bit this will launch the program as a 32 bit process. However the x64 setup only installs a small subset of the Win32 DLLs. See also here for more information on this option.
  • I noticed that the Stemmer.Cvb.Aux and the Stemmer.Cvb.Forms assemblies had been added to the references. These are only needed when working with the Forms display - Stemmer.Cvb.Wpf does not rely on them and I have therefore removed them.
2 Likes
#3

… as I just learned there hast been a recent change to the Stemmer.Cvb.Wpf.dll that introduced a dependency on the Stemmer.Cvb.Forms.dll and (by induction) to the Stemmer.Cvb.Aux.dll if you use the GenApiGrid in WPF. So my removal of these two references might have been premature - sorry for that!

#4

thanks for the answer !
i dont want to use ZoomAdorner, I would like to use a mouse click to zoom (with a fix zoom value) where was the mouse click. And if it is possible, to block the zoom and pan with mouse wheel.
Have you got a solution ?

#5

The latter is quite easy: Just register the PreviewMouseWheel event on disp_img and set the event argument’s Handled member to true - this will prevent the event from propagating into the display and therefore disable the mouse wheel zoom:

MainWindow.xaml

...
<cvb:Display Grid.Row="1" Grid.Column="1"
             Name="disp_img" 
             HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
             MouseDoubleClick="Disp_img_MouseDoubleClick" 
             ZoomCenterChanged="Disp_img_ZoomCenterChanged"
             MouseOverInfoTypes="MouseCursor" 
             PreviewMouseWheel="Disp_img_PreviewMouseWheel" />
...

MainWindow.xaml.cs

private void Disp_img_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
  // stop mouse wheel event in its track...
  e.Handled = true;
}

For zooming by means of clicking I have modified your double click event slightly so that left click zooms in and right click zooms out:

private void Disp_img_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
  // determine zoom factor to apply (current implementation: zoom in by
  // a factor of sqrt(2) when left double-clicking, zoom out by a factor
  // of sqrt(2) when right double-clicking).
  var zoomTarget = disp_img.ActualZoomFactor;
  if (e.LeftButton == MouseButtonState.Pressed)
    zoomTarget *= Math.Sqrt(2.0);
  else if (e.RightButton == MouseButtonState.Pressed)
    zoomTarget /= Math.Sqrt(2.0);
  else
    return;
  // zoom factor might become excessively large or small and Display does
  // not automatically apply an upper or lower limit!
  if (zoomTarget > 64.0)
    zoomTarget = 64.0;
  if (zoomTarget < disp_img.StretchZoomFactor)
    zoomTarget = disp_img.StretchZoomFactor;        
  var zoomCenter = disp_img.TranslatePointToImage(e.MouseDevice.GetPosition(disp_img));
  disp_img.ZoomFactor = zoomTarget;
  disp_img.ZoomCenter = zoomCenter;
}

And here is the entire modified sample: CVB_TEST_ZOOM_Modified_2.zip (10.5 KB)

As it happened, I have noticed that the (unused) zoom adorner might actually run into a NullReferenceException. If that is the case for you as well, I recommend using this updated fileset: CVB.Net_1.48.x.x.zip (1.6 MB)
(either install it in the GAC or copy it to your %CVB%\Lib\Net folder)

#6

thanks.
I update the file with CVB.net.1.48.x.x, but since I do that, cvb:Display doesn’t exist in namespace “http://www.commonvisionblox.com/wpf” !
Do you know why ?

#7

Nope, not really… Worked on my end.:thinking: What happens if you remove the reference to the Stemmer.Cvb.*.dlls and add them again?

#8

I remove all of them and add them again.
i have the same error :


But this error does not prevent the compiler from compiled … only the designer !

#9

Hi @algoptic,

I am sorry, I don’t see a similar issue in the designer. Does it still happen when you close Visual Studio, then remove the obj and bin folder in the project directory and then open it again?

#10

Ah, only the Designer. Good input. Then the DLLs are not trusted.

You can change that by opening the properties of the DLLs in the Windows Explorer via right click. On the first tab will be a text that the DLL is downloaded from the internet and thus is not trusted. Check the check box and apply the setting with ok.