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.
Related
I've developed a simple Histogram control that shows the distribution of grayscale colors (1 to 256 bins) in a live image. The control renders rectangles in an ItemsControl whose ItemsContainer is a ViewBox. Everything is working fine for the most part, however when I resize the grid column (using a GridSplitter) that is hosting the control the fidelity of my histogram begins to degrade.
Here's a couple shots of the histogram at its initial state, and then when it has been resized horizontally (notice the dark vertical lines in the forest of green rectangles...it gets worse the smaller I go):
Here's the XAML that renders the histogram:
<ItemsControl x:Name="_Histogram" Margin="1,3"
ItemsSource="{Binding HistogramCollection}"
VerticalAlignment="Bottom">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<Grid>
<Viewbox Stretch="Fill" MaxHeight="100" >
<ItemsPresenter />
</Viewbox>
</Grid>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Rectangle Fill="LimeGreen"
Stretch="Fill"
Height="{Binding Bin}"
MinWidth="1"
StrokeThickness="0"
VerticalAlignment="Bottom"
HorizontalAlignment="Stretch"
RenderOptions.EdgeMode="Aliased"
UseLayoutRounding="True"
MouseEnter="Rectangle_MouseEnter"
MouseLeave="Rectangle_MouseLeave"
/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Any thoughts? My guess is that WPF is throwing out some Visuals in order to evenly distribute the rest.
I've experimented with using a Polygon in lieu of ItemsControl and Rectangles to distribute my bin points and the behavior goes away, however, I need the ability to MouseOver the histogram and show a popup (among other things, e.g. select a range of bins and update properties in my ViewModel). If you know of a way, using the Polygon approach, that I can hover in the green area and determine that I'm over a specific bin I'm definitely open to that.
UPDATE:
Removing RenderOptions.EdgeMode="Aliased" on the Rectangle XAML seems to solve the problem of black line glitches. Though it does render somewhat pale in the Designer (using d:DesignData), but it seems to render fine at runtime. I'm going to hold off on marking as "Answered" until others have had a chance to chime in. I'm really interested in the polygon approach because I get a crisper histogram when resizing to a larger width (the wider I make the histogram, the more pixelated the peaks get, i.e. the peaks are flat because of the width of the rectangle, which presents as a jagged plot instead of smooth curved plot). If only Point had a mouse over handler :D.
This is more of XAML question for silverlight.
<Mobile:DevicePushpinTemplateSelector
m:MapLayer.Position="{Binding Location}"
ZoomLevel="{Binding ZoomLevel, ElementName=MainMap}"
Content="{Binding}">
<Mobile:DevicePushpinTemplateSelector.DotTemplate>
<DataTemplate>
<Ellipse Width="8" Height="8" Stroke="Black" Fill="{Binding IsGPSDataRecent, Converter={StaticResource BoolToGreenRedBrushConverter}}" StrokeThickness="1">
<ToolTipService.ToolTip>
<TextBlock Text="{Binding DisplayId}" />
</ToolTipService.ToolTip>
</Ellipse>
</DataTemplate>
</Mobile:DevicePushpinTemplateSelector.DotTemplate>
<Mobile:DevicePushpinTemplateSelector.NumberedTemplate>
<DataTemplate>
<Border x:Name="border" Background="{Binding IsGPSDataRecent, Converter={StaticResource BoolToGreenRedBrushConverter}}" BorderBrush="Black" BorderThickness="2" Padding="2" Height="20" CornerRadius="8">
<TextBlock VerticalAlignment="Center" Text="{Binding DisplayId}" />
</Border>
</DataTemplate>
</Mobile:DevicePushpinTemplateSelector.NumberedTemplate>
</Mobile:DevicePushpinTemplateSelector>
On XAML above I have 2 different templates based on map zoom level. When it is zoomed out - it shows smaller ellipse, when user zooms closer - I increase size of pushpin.
2 issues:
WIth a lot of pushpins it get's really slow, I beleive it's due to template selection.
I want it to be different. I want to create "IsSelected" property so all pushpins will be the same on all zoom levels but when user clicks on pushpin - it expands in size.
I wonder how do I code "selection" part. I want only one pushpin to be selected at time. I can bind to property and make pushpin parts visible/invisible but I'm not sure how to code "selection" piece. Should it be Button?
When doing a windows phone app I had the issue of many pins causing "lag" the easiest way around that is to only show pins within a certain radius of the centre of the map and remove the others until they come into the radius.
Cheers
Mark
I have an ItemsControl presenting a list of buttons. Each button has an image as it's content (png), but the image looks slightly different for each row.
The below image is magnified version of what I'm seeing:
Here is the xaml:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Name="tb1">hello</TextBlock>
<Button Height="{Binding ElementName=tb1, Path=ActualHeight}" Padding="0,-3,-3,-3" BorderBrush="Transparent" Background="Transparent" >
<Image Stretch="Fill" Source="stock_standard_filter.png" Margin="0">
</Image>
</Button>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I've had a similar issue previously and was able to solve it using SnapsToDevicePixels="True", but that solution is not working this time. I've also tried UseLayoutRounding="True" and RenderOptions.EdgeMode="Aliased"
The height of the button is bound so the image will be stretched to fill the button. Because WPF uses doubles (1/96 inch units) there is bound to be some rounding off. SnapsToDevicePixels and Layout rounding might help when you use them on the StackPanel but as long as you stretch the image it will get blurred.
My best guess is to set "Stretch to None" and experiment with SnapsToDevicePixels and Layout rounding.
Here's my layout.
<Window>
<StackPanel Orientation="Vertical">
<StackPanel HorizontalAlignment="Stretch" Height="30">
</StackPanel>
<Canvas HorizontalAlignment="Center" Width="1020">
<!--i want this to take the remaining full height of the screen-->
<Canvas x:Name="bottomInfoBar" Canvas.Bottom="0" Width="720" Height="39">
<!--I want this at the very bottom of the screen-->
</Canvas>
</Canvas>
</Window>
I want the canvas to take the full height of the window so that the 'bottomInfoBar' always remains at the very bottom of the user's screen. However if i don't specify a height for the canvas 'bottomInfoBar' appears at the very top. How do i achieve this? Please help.
Easiest way:
<Window>
<DockPanel>
<Whatever x:Name="bottomInfoBar" DockPanel.Dock="Bottom"/>
<PrimaryContent/>
</DockPanel>
</Window>
Based on your question, you really should read about WPF's layout system before you write another line of code. You'll save yourself a world of pain if you understand that before proceeding.
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.