3

INTRODUCTION:

I am trying to learn WPF on my own, by reading official documentation and using Internet to find help.

I come from C++ and raw WinAPI background, but I do have some experience with C# and .NET, including WinForms.

I have .svg file that should be displayed in a main window. Application should offer zooming capability and should be able to scroll the image in case it is too big to fit inside main window.

Since WPF can not render .svg, I have used Inkscape to convert the file into .xaml so I can render it successfully.

MY EFFORTS TO SOLVE THE TASK:

I have managed to solve scrolling part, thanks to certain questions here, on SO. Zooming works too, but the overall result is not satisfying. That is the reason why I ask here for help. At the moment of writing this post, I am searching online for a solution ( still no progress though... ).

PROBLEM:

When zooming in, or out, image is not positioned properly, so scroll bars can not show it fully.

Since English is not my native, and I am novice in WPF, I have very hard time explaining the problem. Still, I have taken snapshots that will demonstrate what I was talking about.

Let me first start with the image of the main window, when it is first loaded to the screen:

enter image description here

Problems that occur after zooming in, and zooming out are shown bellow, respectively:

enter image description here

enter image description here

You can clearly see that I can not scroll up in the first image (when zooming in) in order to see top of the tiger's head.

On second image we can see that tiger is horribly misplaced, and bottom horizontal scroll bar is not seen, so I can not see the bottom of the tiger's head.

RELEVANT INFORMATIONS:

I have taken this image and converted it into XAML using Inkscape. XAML was too big to post here (I tried) so I am showing the bare minimum of the XAML I have so far:

<Window x:Class="Testing.MainWindow"
        Name="myMainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" KeyUp="myMainWindow_KeyUp">
    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <!-- Canvas, and its drawing, were created with Inkscape -->
        <Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Name="svg2" Width="494.44705" Height="510.55356">
            <Canvas.RenderTransform>
                <TranslateTransform X="183.99798" Y="144.4264"/>
            </Canvas.RenderTransform>
            <!-- many drawing commands, omitted for brevity -->
        </Canvas>
    </ScrollViewer>
</Window>

Everything from Canvas element, including its Height and Width, and TranslateTransform was created by Inkscape. That is why I am not allowed to change that content. As you can see, I have placed canvas inside scrollviewer.

Scrolling worked fine, but after I apply zooming it malfunctions.

I have decided to zoom in when user presses +, and zoom out when user presses -, for start. The handling of the KeyUp event is shown below.

private void myMainWindow_KeyUp(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Add)
    {
        Matrix m = svg2.LayoutTransform.Value;

        m.M11 += 0.5;
        m.M22 += 0.5;

        svg2.LayoutTransform = new MatrixTransform(m);
    }

    if (e.Key == Key.Subtract)
    {
        Matrix m = svg2.LayoutTransform.Value;

        m.M11 -= 0.5;
        m.M22 -= 0.5;

        svg2.LayoutTransform = new MatrixTransform(m);
     }
 }

The entire XAML and code behind can be found here.

QUESTION:

What am I doing wrong? How can I tweak the submitted code so zooming works properly?

netaholic
  • 1,345
  • 10
  • 22
AlwaysLearningNewStuff
  • 2,939
  • 3
  • 31
  • 84
  • @netaholic: *The dashed line is a visual representation of element being focused.* Yes, after testing it for a while, I think that scrollviewer gets the keyboard focus each time i press key. That would explain the dashes. *Is it possible for you to share your entire project? * Ofcourse, just give me time to paste it on pastebin. I will add the link in original post as a result of an edit. You will be notified. – AlwaysLearningNewStuff Sep 21 '15 at 14:59
  • @netaholic: I have added the link in the `RELEVANT INFORMATION` section, at the very bottom. Thank you for your time. Good luck. – AlwaysLearningNewStuff Sep 21 '15 at 15:03

2 Answers2

1

So. Canvas is a lightweight container, designed to arrange elements in specified positions. Canvas can display elements outside of its boundaries, but if you set ClipToBounds="True" on Canvas, then, unsurprisingly, it will clip anything that is out of its boundaries.

If you take a look at your xaml:

 <Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Name="svg2" Width="494.44705" Height="510.55356">
                <Canvas.RenderTransform>
                    <TransformGroup>
                        <TranslateTransform X="183.99798" Y="144.4264"/>
                    </TransformGroup>
                </Canvas.RenderTransform>

You'll see, that your Canvas is actually moved by TranslateTransform. In the image below you can see actual rectangle position, stroked in red. If you will set ClipToBounds="True" then everything outside of this rectangle is gonna be clipped. (I recommend you to check program called Snoop, it's very useful)

enter image description here

When I have discovered that your canvas has transform, I've desided to re-generate the image, that you have. There are 2 common ways to do it: by hands (printing as XPS document and extracting relevant xaml) or by Inkscape. I've tried the first approach, but failed. So, I've used last version of Inkscape. What I've payed attention to are following boxes:

enter image description here

Then I've saved svg as xaml with "Compatible with Silverlight" option checked. The result was following:

 <Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Name="svg2" Width="900" Height="900">
        <Canvas.RenderTransform>
            <TranslateTransform X="0" Y="0"/>
        </Canvas.RenderTransform>
        <Canvas Name="g4">
         <!-- data below -->

And everything worked without glitches. Here is the xaml I've got http://pastebin.com/tRin96Hi So it was all about lines not fitting in canvas rectangle.

UPDATE Step-by-step on how I have set x & y to 0 in Inkscape.

  1. Downloaded latest version of Inkscape (0.91)
  2. Installed it
  3. Downloaded an svg image
  4. Opened it with "Open with... -> Inkscape"
  5. Ctrl + A to select all figures
  6. Step 5 enables x & y boxes. Print 0 in box and press Enter (or switch to other box) to apply changes. Apply 0 for both x and y boxes.
  7. (Optional) File - Document properties - Page - Height & Width, if needed to crop
  8. Saved svg as xaml with "Compatible with Silverlight" option checked.
netaholic
  • 1,345
  • 10
  • 22
  • I can not export from Inkscape with transformation removed. Can you please edit your answer with detailed step by step guide? I will try to figure this out myself while I wait. I have upvoted for now, and will officially accept after I figure out how to do what you suggested. Thank you for your help. Best regards. – AlwaysLearningNewStuff Sep 22 '15 at 09:54
  • @AlwaysLearningNewStuff done. What makes an issue exactly? Please notice, that it's TranslateTransform that have to be with x and y set to zero. MatrixTransform in a child canvas has to stay there with its complicated values – netaholic Sep 22 '15 at 10:03
  • *What makes an issue exactly?* Too many canvases for my poor eyes! *Please notice, that it's TranslateTransform that have to be with x and y set to zero.* In my version of the XAML there is nothing written, which is effectively the same as `` but it confused me. *MatrixTransform in a child canvas has to stay there with its complicated values* That too added to the confusion. After following your steps, copy/pasting the resulting XAML into my app, everything seems to work. Therefore I am officially accepting your answer ( I have already upvoted it ). Thank you! – AlwaysLearningNewStuff Sep 22 '15 at 10:16
  • @AlwaysLearningNewStuff one more thing: you might wanna look up `ViewBox` WPF panel. It's often used to host `Canvas`. I think you can make a smooth zooming by applying changes to viewbox. Have a nice day – netaholic Sep 22 '15 at 10:17
  • *you might wanna look up ViewBox WPF panel. It's often used to host Canvas.* Ofcourse, I will take your advice and try it myself, but I really see no point for viewbox at the moment... *I think you can make a smooth zooming by applying changes to viewbox.* I do not know how to use ViewBox to achieve that. Can you suggest any code example or tutorial? Anyway, I will try to add panning support now, and zooming on mouse wheel. If interested, I can send you the result on that e-mail you provided in the comment... Again, thank you so much! – AlwaysLearningNewStuff Sep 22 '15 at 10:24
  • @AlwaysLearningNewStuff I'm not sure that this approach is beneficial, but here http://stackoverflow.com/questions/10372560/zooming-to-mouse-point-with-scrollview-and-viewbox-in-wpf guy has a piece of code. The change will be, that you will change viewbox dimension and work with scrollviewer, instead of working with transform matrix. You definetly should just try to host canvas in a viewbox and a viewbox in a scrollviewer and take a look on how different Stretch options behave. – netaholic Sep 22 '15 at 10:32
0

Perhaps using a ScaleTransform instead of a MatrixTransform may help.

MSDN - ScaleTransform

indigophoenix
  • 101
  • 1
  • 5