WPF element positioning on a Canvas - c#

I have a point on a canvas that I want to place an ellipse. I want the centre of the ellipse to be over this point. At the moment the top left most edge of the ellipse is over this point.
I know I can shift the ellipse programmatically on the canvas but I was wondering if there is a way to tell WPF to centre the element over the point instead of sizing it from the top left???

I do not know of any in built in feature in Ellipse to set its center on a point, but you can extend the Ellipse class to do it.
Add this class to project
public static class EllipseX
{
public static void SetCenter(this Ellipse ellipse, double X, double Y)
{
Canvas.SetTop(ellipse, Y - ellipse.Height/2);
Canvas.SetLeft(ellipse, X - ellipse.Width/2);
}
}
Then in xaml create the Ellipse
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Canvas Background="LightGray">
<Ellipse
Name="myEllipse"
Fill="Red"
Height="75"
Width="75"
/>
</Canvas>
</Window>
Then write int following code in code behind:
myEllipse.SetCenter(200,200);
The advantage of this is that you do not have to repeat the logic of finding center in every ellipse you create.
Hope this helps.

No there is no such way. Top Left is a top left, because it's a top left :). Alternatively instead of shifting ellipse you can shift point, if you know ellipse dimensions.

You could apply a TranslateTransform to the Ellipse, but that requires you to know its width and height.

I had a similar problem setting the Center of a ScaleTransform in a style of different sized controls.
Ended up using a converter to bind to the ActualWidth/ActualHeight divided by 2. THe same should work for you with a TranslateTransform as Rune Grimstad mentioned.
<ScaleTransform CenterX="{Binding ActualWidth, Converter={StaticResource divisionConverter}}"
CenterY="{Binding ActualHeight, Converter={StaticResource divisionConverter}}"
ScaleX="1.2"
ScaleY="1.2" />

Related

Rectangle UI on Windows Phone app?

I have a xaml page that I put a rectangle on a grid (grid covers whole screen). How do I go about getting the coordinates of the Rectangle's upper left corner?
Xaml class:
<Page
x:Class="JunkyJunk.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:JunkyJunk"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Canvas>
<Rectangle x:Name="TestRectangle"
Fill="#FFF4F4F5"
HorizontalAlignment="Left"
Height="100"
Stroke="Black"
VerticalAlignment="Top"
Width="100"
Loaded="TestRectangle_Loaded" Canvas.Left="137" Canvas.Top="245"/>
</Canvas>
So lets just say I just place this rectangle onto a canvas (changed it from a grid). How would I get the coordinates of the rectangle's upper left corner?
Thanks
Figured it out.
double x = Canvas.GetLeft(TestRectangle);
double y = Canvas.GetTop(TestRectangle);
You can use a GeneralTransform to convert a point or rectangle from one UIElement's coordinate system to another's.
The rectangle's top left coordinates will always be 0,0 in the rectangle's coordinates, so if you translate that to your canvas' coordinates then you can look at the new value to see where the Rect is.
This will work with any two UIElements, so you could keep your Grid and not have to rely on Canvas.Left and Canvas.Top.
// Rectangle's bounds in its own coordinates
Rect testRectLocalBounds = new Rect(0, 0, TestRectangle.ActualWidth, TestRectangle.ActualHeight);
// Transforms from TestRectangle's to this page's and to TestCanvas' coordinates
GeneralTransform transformToPage = TestRectangle.TransformToVisual(this);
GeneralTransform transformToCanvas = TestRectangle.TransformToVisual(TestCanvas);
// TestRectangle's boundaries in the Page's and Canvas' coordinates
Rect testRectPageBounds = transformToPage.TransformBounds(testRectLocalBounds);
Rect testRectCanvasBounds = transformToCanvas.TransformBounds(testRectLocalBounds);
Debug.WriteLine("Rect relative to page: {0} to canvas: {1}", testRectPageBounds, testRectCanvasBounds);

Scrolling problems when using ScaleTransform in Panorama/Pivot/RadSlideView item

I'm trying to implement zoom-functionality in a RadSlideView ItemTemplate. I'm doing this by using a ViewportControl with a Canvas and then applying a RenderTransform (ScaleTransform) to a StackPanel in the Canvas. Similar to the SDK-sample found here.
The problem I have is that the ScaleTransform seems to be affecting the swipe-gesture used to change item in the SlideView/Panorama/Pivot control. E.g. if the ScaleTransform is set to 0.1 it seems like I only need to swipe 1/10th of the length to change item compared to using a ScaleTransform of 1.0.
I found that if I set IsHitTestVisible to false on the ItemTemplate the swiping works like I want. But this is not a solution since I sometimes need to be able to pan the content vertically while still being able to change item by swiping horizontally.
So my question is how can I solve this?
For reference the XAML looks like this:
<Controls:RadSlideView Name="SlideView" ItemsSource="{Binding Pages}" IsLoopingEnabled="False" SelectionChanged="RadSlideView_SelectionChanged" CacheMode="BitmapCache" ManipulationStarted="SlideView_ManipulationStarted" ManipulationCompleted="SlideView_ManipulationCompleted" ManipulationDelta="SlideView_ManipulationDelta">
<Controls:RadSlideView.ItemTemplate>
<DataTemplate>
<ViewportControl x:Name="SlideViewViewport" ViewportChanged="SlideViewViewport_ViewportChanged" Loaded="SlideViewViewport_Loaded">
<Canvas>
<StackPanel>
<Image Source="{Binding Image}" Stretch="Fill" Width="{Binding ElementName=SlideView, Path=DataContext.PageWidth}" Height="{Binding ElementName=SlideView, Path=DataContext.PageHeight}" CacheMode="BitmapCache"/>
<StackPanel.RenderTransform>
<ScaleTransform x:Name="xform"/>
</StackPanel.RenderTransform>
</StackPanel>
</Canvas>
</ViewportControl>
</DataTemplate>
</Controls:RadSlideView.ItemTemplate>
I have also looked at Teleriks RadPanAndZoom-control to avoid implementing my own zoom-functionality, but since I sometimes need to place two pictures side by side and zoom them as if they were one I don't think I can use it.
The problem is that ScaleTransformation scales your picture, but doesn't change it's height and width. Only if Height And Width are overflowing scrollviewer you can scroll the content

Horizontal image scaling with ScaleTransform in WPF

I have an image in a WPF window with the default Stretch setting, Uniform, and am making an attempt to make it fill the screen horizontally. I do not wish to use a different Stretch setting as this is supposed to a learning experience. The image dimensions being loaded are 420x800. This is the XAML for the window..
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Red" Height="1200" Width="840">
<Image Name="Image" Source="{Binding SourceUri}">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform x:Name="Scale" />
<TranslateTransform x:Name="Translate" />
</TransformGroup>
</Image.RenderTransform>
</Image>
</Window>
On the code-behind, I am attempting to calculate the scaling to zoom the image to fill the horizontal screen and I am using translate transform the move it to the center of the screen. The following bit of code is obviously wrong...
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace WpfApplication1 {
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
DataContext = this;
double ImageWidth = 420;
Scale.ScaleX = Width / ImageWidth;
Translate.X = -(ImageWidth / 2);
}
public string SourceUri {
get {
return #"C:\Users\Roel\Desktop\test.png";
}
}
}
}
I am attempting to understand how stretching and transformations are working together but I am having difficulty with this. I would appreciate all insights, even references to detailed explanations, as I have trouble finding any informational source explaining clearly and concisely how the transformations are applied.
You would usually just do this:
<Image Name="Image" Source="{Binding SourceUri}" Stretch="Fill"/>
In case you really need to calculate the stretch transformation manually, you would only need a ScaleTransform, no TranslateTransform, and you would put that into the LayoutTransform of the Image control. Moreover, the Image control would have to be placed into a Grid, which provides the size of the Windows's "client area". You can't calculate anything based on the Window's Width (or ActualWidth) as that includes the width of the Window's borders.
<Grid SizeChanged="Grid_SizeChanged">
<Image Name="image" Source="{Binding SourceUri}">
<Image.LayoutTransform>
<ScaleTransform x:Name="scale"/>
</Image.LayoutTransform>
</Image>
</Grid>
In the Grid's SizeChanged handler you would calculate the scaling as shown below.
private void Grid_SizeChanged(object sender, SizeChangedEventArgs e)
{
scale.ScaleX = e.NewSize.Width / image.Source.Width;
scale.ScaleY = e.NewSize.Height / image.Source.Height;
}

Making a control invisible when its out of bounds of a parent control? in WPF

I'm trying to put a bigger MediaElement into a smaller Canvas on WPF.
Lets say i'm putting 600x400 media into a 400x300 Canvas with Canvas.Top = -50, Canvas.Left = -100.
And i don't want the sides that are out of bounds to be displayed, in this case 50 pixels from top and bottom, 100 pixel from right and left of my media should be invisible.
How can i achieve this? Thanks for all the help!
What you are asking for is called "Clipping". You need to add a RectangleGeometry to the Canvas.Clip property:-
<Canvas Width="400" Height="300">
<Canvas.Clip>
<RectangleGeometry Rect="0 0 400 300" />
</Canvas.Clip>
<!-- Your content here --->
</Canvas>

WPF databinding problem

I have a grid inside a canvas on a tab.
The grid contains a large bitmap image,
I have(tried to) bound the size of the grid to the size of the tab and also have a five pixel margin around the grid.
imageTab.cs
public ImageTab(SendInfo sendInfo, int numImge, int numAccs)
{
imageDisplay = new ImageDisplay(sendInfo, numImge, numAccs);
imageDisplay.ClipToBounds = true;
CreateCanvas();
}
private void CreateCanvas()
{
Canvas canvas = new Canvas();
canvas.Children.Add(imageDisplay);
this.AddChild(canvas);
}
ImageDisplay.xaml
<UserControl x:Class="MyProj.ImageDisplay">
<Grid Margin="5,5,5,5" Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=TabControl, AncestorLevel=1}, Path=ActualHeight}">
<Image/>
</Grid>
</UserControl>
The grid comes off the bottom of the tab area slightly causing the bottom of the image to be cut off.
Is there a problem with my databinding, do I need to apply some sort of offset to it? (size of tab - 10pixels for the margin?)
You don't need to set the Height property at all (also realize that it is incorrect to do so as you have it when you consider the 5 pixel margin, i.e., it would be off by 10 pixels).
Just leave VerticalAlignment and HorizontalAlignment at their default values (which is Stretch) to get the effect you are after here.
Try this on a new Window to see what I mean:
<Window x:Class="WpfApplication9.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="438" Width="587" Background="Pink">
<Grid Background="Black" Margin="5">
</Grid>
</Window>
The grid here will be black and will always stretch to the size of the window, using a 5 pixel margin which you will see because the Window's back color is pink.

Categories

Resources