Zoom control to WPF Form - wpf

How can I implement a zoom control to my wpf forms similar to the one avaialble in the visual studio designer?
thanks!

Put your stuff into a grid, bind the grid's scale render transformation to a slider (slider should have min value of 1):
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="0.867*"/>
<RowDefinition Height="0.133*"/>
</Grid.RowDefinitions>
<Slider x:Name="slider" Grid.Row="1" Minimum="1"/>
<Grid RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform
ScaleY="{Binding Path=Value, ElementName=slider}"
ScaleX="{Binding Path=Value, ElementName=slider}"/>
</TransformGroup>
</Grid.RenderTransform>
<TextBox Text="TextBox" Height="45.214"
VerticalAlignment="Top" Margin="194,139,209,0"/>
<TextBox VerticalAlignment="Bottom"
Text="TextBox" Margin="194,0,209,118.254" Height="48.96"/>
</Grid>
</Grid>

Maybe you could try out the Zoom Control which is part of WPF Extensions available on Codeplex:
alt text http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=wpfextensions&DownloadId=66810

You should have a look at this article by Mitsu Furuta (don't worry about the funny title !). I'm not sure whether it meets your requirements exactly, but it could give you some ideas...

To get a professional Zoom Control for WPF check out the ZoomPanel.
It is not free, but is very easy to use and has many features - animated zooming and panning, support for ScrollViewer, mouse wheel support, included ZoomController (with move, zoom in, zoom out, rectangle zoom, reset buttons). It also comes with many code samples.

Related

WPF Control, UserControl, Template confusion

Disclosure:
I am new to WPF, about a week into it.
Problem:
I am trying to modify the behavior of a GridSplitter, to make it snap to interesting positions, to show a label (that follows the splitter) with current position, to have a context menu driven from said label, etc. I have prototyped all of this successfully on one gridsplitter in one simple test application, with a combination of XAML and some code behind.
Of note is that because the GridSplitter can't host content, I placed the label in the same grid cell as the splitter so that they move together.
So far so good....
Now I wish to replicate my work so that I can use my new GridSplitter functionality in place of the native control in many locations, and furthermore, I wish to have two variants, a horizontal and a vertical. Sounds like inheritance...create a subclass derived from GridSplitter and add in the additional functionality. But all of the reading I have done leaves me wondering how to go about this, and if this is even possible without starting over again and building my own GridSplitter from scratch?
Ideas welcome. Until then I will resume the fetal position.
Thanks
This answer might help you resolve your issue: How to make GridSplitter to "snap" into another element?
By subscribing to the GridSplitterDragCompleted event, you can insert your logic to snap to "interesting" positions.
You should
create a new control derived from GridSplitter.
subscribe to DragCompleted event to implement snapping functionality like DLeh mentioned.
add a few new properties for Label , ContextMenu etc.
supply a style for your new control.
This answers how to place content in the splitter
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Row 0" Background="Orange"/>
<!--<GridSplitter Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Stretch" Height="20" Background="Purple"/>-->
<GridSplitter Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Stretch">
<GridSplitter.Template>
<ControlTemplate TargetType="{x:Type GridSplitter}">
<TextBlock Text="TextBlock splitter" Background="Yellow" FontWeight="Bold"/>
</ControlTemplate>
</GridSplitter.Template>
</GridSplitter>
<Button Grid.Row="2" Content="Row 0" Background="Salmon"/>
</Grid>

Error trying to freeze a Rectangle filled with a BitmapCacheBrush

I'm trying to Freeze a BitmapCacheBrush, but when I call Freeze it errors stating it can't be frozen.
What I'm trying to do is fill a Rectangle with a BitmapCacheBrush and then at some point, Freeze it so I can then animate the Rectangle and reuse the source Grid for something else (whilst animating the Rectangle).
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50*"></RowDefinition>
<RowDefinition Height="50*"></RowDefinition>
</Grid.RowDefinitions>
<Grid x:Name="LISTING">
<Grid.CacheMode>
<BitmapCache RenderAtScale="1" SnapsToDevicePixels="True"/>
</Grid.CacheMode>
<Rectangle x:Name="Rectangle1" Fill="Red" />
<Label Content="Test" FontSize="20" Foreground="Black" />
<Button x:Name="Button1" Click="Button1_Click"/>
</Grid>
<Rectangle Grid.Row="1" x:Name="Rectangle2" >
<Rectangle.Fill>
<BitmapCacheBrush x:Name="BMCB" Target="{Binding ElementName=LISTING}"/>
</Rectangle.Fill>
</Rectangle>
</Grid>
In my test I am trying to see if I can Freeze the BMCB BitmapCacheBrush when the button is clicked, then as a test I want to hide the button and still see the bottom rectangle intact.
I'm wanting to use BitmapCacheBrush for the performance aspect.
Is this even possible?
Thanks
Ben
I would say No: But my only source to prove that is the Freezable documentation in the msdn, which says:
A Freezable can't be frozen if any of the following are true:
It has animated or data bound properties.
It has properties set by a dynamic resource.
It contains Freezable sub-objects that can't be frozen.
So i guess you can't freeze it because of your Target="{Binding ElementName=LISTING}" binding.

Why is my Popup showing opposite the Placement property on some machines?

I have a simple WPF Popup that I am showing when the user clicks a Button.
<Button
x:Name="aButton"
Content="Up/Down"
Width="75"
Height="30"
Click="aButton_Click"
/>
<Popup
PlacementTarget="{Binding ElementName=aButton}"
Placement="Right"
VerticalOffset="-31"
StaysOpen="False"
AllowsTransparency="True"
>
<StackPanel>
<Button Width="45" Height="45" Margin="2,0,2,2" Content="+"/>
<Button Width="45" Height="45" Margin="2,0,2,0" Content="-"/>
</StackPanel>
</Popup>
What is extremely weird ... is that this code works differently depending on what machine it runs on.
I run this code on my main desktop and everything works just fine ... and as it should. I run it on my PDC09 netbook ... and the Popup shows opposite (on the left instead of the right as I told it to with the Placement property).
Why is this? And what can I do about it?
I couldn't find anything via Google ... but a lucky search in the WPF forum, quickly found this post. Note to self: don't forget to search the WPF forums if Google can't find anything.
The answer is that my PDC09 netbook is a Tablet PC at heart, and apparently, Microsoft thought it was a good idea to show the Popup opposite to the Placement property on a Tablet PC that is configured for right-handed people ... such that the Popup doesn't appear under the user's hand.
The solution is to revert to custom Popup placement ... if you don't want this behavior.
I would love to hear about any other ways around this problem.
I fixed this issue by adding a border in the same grid col/row as the desired placement target. Then set this as the placement target instead. By binding the width of this border to the popup content it will adjust it's width automatically therefore the alignment (left or right) is irrelevant. If you want to still control alignment, you can do that by aligning the placement target border.
Hope that makes sense, if not, here is a quick example.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Popup x:Name="StartMenuPopup" Placement="Top" PlacementTarget="{Binding ElementName=PopupTarget}" >
<Border x:Name="PopupBorder">
</Border>
</Popup>
<Border x:Name="PopupTarget" Grid.Row="1" Width="{Binding ActualWidth, Mode=OneWay, ElementName=PopupBorder}"
BorderThickness="0" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<startmenu:TaskBar Grid.Row="1">
<startmenu:TaskBar.StartButton>
<startmenu:ToggleMenu Width="36" x:Name="StartButton"
ImageData="{Binding StartButtonImageData}"
AssociatedPopup="{Binding ElementName=StartMenuPopup}"
IsOpen="{Binding StartMenuOpen, Mode=TwoWay}"/>
</startmenu:TaskBar.StartButton>
</startmenu:TaskBar>
</Grid>
The popup PlacementTarget binds to the PopupTarget border, and the PopupTarget border width binds back to the PopupBorder element. This makes the PopupTarget border the same width as the popup therefore negating the alignment issue.

WPF zoom canvas and maintain scroll position

I have a Canvas element, contained within a ScrollViewer, which I'm zooming using ScaleTransform. However, I want to be able to keep the scroll position of the viewer focused on the same part of the canvas after the zoom operation has finished. Currently when I zoom the canvas the scroll position of the viewer stays where it was and the place the user was viewing is lost.
I'm still learning WPF, and I've been going backwards and forwards a bit on this, but I can't figure out a nice XAML based way to accomplish what I want. Any help in this matter would be greatly appreciated and would aid me in my learning process.
Here is the kind of code I'm using...
<Grid>
<ScrollViewer Name="TrackScrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Canvas Width="2560" Height="2560" Name="TrackCanvas">
<Canvas.LayoutTransform>
<ScaleTransform ScaleX="{Binding ElementName=ZoomSlider, Path=Value}"
ScaleY="{Binding ElementName=ZoomSlider, Path=Value}"/>
</Canvas.LayoutTransform>
<!-- Some complex geometry describing a motor racing circuit -->
</Canvas>
</ScrollViewer>
<StackPanel Orientation="Horizontal" Margin="8" VerticalAlignment="Top" HorizontalAlignment="Left">
<Slider Name="ZoomSlider" Width="80" Minimum="0.1" Maximum="10" Value="1"/>
<TextBlock Margin="4,0,0,0" VerticalAlignment="Center" Text="{Binding ElementName=ZoomSlider, Path=Value, StringFormat=F1}"/>
</StackPanel>
</Grid>
This is not a purely XAML way of doing it, but there is a very nice piece of work on Joeyw's blog titled Pan and Zoom (DeepZoom style) in WPF with links to the source. He has taken some inspiration from DeepZoom and it gives you smooth/animated panning and zooming of content. And if you're using WPF 4 you could probably modify it a little to add some easing functions to the animations to give it an even nicer feel.

Use UIElement as Clip in WPF

Please pardon my ignorance- I'm very new to WPF.
I am looking to implement a minor, visual effect in my application that gives the look of "inner" rounded corners. The window in question has a dark border that encapsulates several UIElements, one of which is a StatusBar, located at the bottom of the window. This StatusBar has a dark background that matches the window's border. Above the StatusBar is a content view, which is currently a Grid- its background is semi-transparent (I think that this is something of a constraint- you can see through the content view to the desktop below). I would like for the content view (represented by the transparent, inner area in the figure below) to have the look of rounded corners, though I expect to have to sort of create the illusion myself.
(Can't post the image because I'm a lurker and not a poster- please find the drawing here)
My first approach was to add a Rectangle (filled with the same, dark color as the border) immediately above the StatusBar and to assign a Border with rounded corners to its OpacityMask (similar to the solution proposed by Chris Cavanagh**). Sadly, the effect that is produced is the exact opposite of that which I am trying to achieve.
I understand that the Clip property can be of use in this sort of situation, but it seems to me that using any sort of Geometry will prove to be inadequate as it won't be dynamically sized to the region in which it resides.
EDIT: Including my XAML:
<Grid Background="{StaticResource ClientBg}" Tag="{Binding OverlayVisible}" Style="{StaticResource mainGridStyle}">
<DockPanel LastChildFill="True">
<!-- Translates to a StackPanel with a Menu and a Button -->
<local:FileMenuView DockPanel.Dock="Top" />
<!-- Translates to a StatusBar -->
<local:StatusView DockPanel.Dock="Bottom" />
<!-- Translates to a Grid -->
<local:ContentView />
</DockPanel>
</Grid>
Any pointers are more than welcome- I'm ready to provide more indepth detail if necessary.
** http://www.dotnetkicks.com/wpf/WPF_easy_rounded_corners_for_anything
EDIT: Now I got what you mean. In fact you can use Path + OpacityMask approach. You have to draw "inverted" path, to use it as opacity mask. But I have simpler and faster solution for you :). Use Border + CornerRadius, and fill the gaps with solid paths. Just try the following code in Kaxaml and let me know if this is what you were looking for:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="240"
Height="320"
AllowsTransparency="True"
Background="Transparent"
WindowStyle="None">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="24"/>
<RowDefinition Height="*"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<Border Background="Black"/>
<Border Grid.Row="1" BorderBrush="Black" BorderThickness="5">
<Grid>
<Border Background="White" CornerRadius="0, 0, 5, 5" Opacity="0.7"/>
<Path
Width="15"
Height="15"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Data="M10,10 L5,10 L5,5 C4.999,8.343 6.656,10 10,10 z"
Fill="Black"
Stretch="Fill"/>
<Path
Width="15"
Height="15"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Data="M10,10 L5,10 L5,5 C4.999,8.343 6.656,10 10,10 z"
Fill="Black"
Stretch="Fill">
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="-1"/>
<TranslateTransform X="15"/>
</TransformGroup>
</Path.RenderTransform>
</Path>
</Grid>
</Border>
<Border Grid.Row="2" Background="Black"/>
</Grid>
</Window>
PS: You can simplify this solution by avoiding render transforms, but you got the idea.

Resources