I am new to WP7 / Silverlight / C# programming and I'm currently putting together a simple magnifying app to get to grips with a few things. In order to provide 'zoom in' and 'zoom out' functionality I successfully managed to use a ScaleTransform on the UIElement which contains the video feed.
As I have developed the app further I realised that I want to accomodate the orientation changing during the use of the app and ensure that the video feed responds accordingly (The app is fixed in landscape mode but a user may want to 'turn the phone over' for some reason). To address this I created and applied a RotateTransform and linked into the OrientationChanged event.
All of this works fine but when I try to zoom (using the ScaleTransform) after I have changed the orientation then the video feed zooms but flips the feed back to the 'default' orientation and therefore show upside down.
Given this I figured I needed to apply both transforms when zooming in, so I created a TransformGroup and added the ScaleTransform and RotateTransform to it. However the zoom function will not work with this and none of the transform's appear to be applied.
Has anybody else encountered problems when trying to apply a TransformGroup?
I've included a snippet of the zoom in and orientation code below for reference - apologies in advance if I am doing things the long way round but bear in mind I'm still learning.
Any help would be appreciated.
Thanks in advance,
Craig.
UIElement videocontainer;
RotateTransform rotatetransform = new RotateTransform();
void MainPage_OrientationChanged(object sender, OrientationChangedEventArgs e)
{
switch (Orientation)
{
case PageOrientation.LandscapeLeft:
rotatetransform.Angle = 0;
break;
default:
rotatetransform.Angle = 180;
break;
}
rotatetransform.CenterX = 320;
rotatetransform.CenterY = 240;
videocontainer.RenderTransform = rotatetransform;
private void ZoomIn_Click(object sender, EventArgs e)
{
if (zoom < 7)
{
switch (Orientation)
{
case PageOrientation.LandscapeLeft:
ScaleTransform myscaletransform1 = new ScaleTransform();
myscaletransform1.ScaleX = myscaletransform1.ScaleX * 1.25;
myscaletransform1.ScaleY = myscaletransform1.ScaleY * 1.25;
myscaletransform1.CenterX = 320;
myscaletransform1.CenterY = 240;
TransformGroup zoomintranformgroup1 = new TransformGroup();
zoomintranformgroup1.Children.Add(myscaletransform1);
zoomintranformgroup1.Children.Add(rotatetransform);
videocontainer.RenderTransform = zoomintransformgroup1;
zoom++;
break;
default:
ScaleTransform myscaletransform2 = new ScaleTransform();
myscaletransform2.ScaleX = myscaletransform2.ScaleX * 1.25;
myscaletransform2.ScaleY = myscaletransform2.ScaleY * 1.25;
myscaletransform2.CenterX = 320;
myscaletransform2.CenterY = 240;
TransformGroup zoomintranformgroup2 = new TransformGroup();
zoomintranformgroup2.Children.Add(myscaletransform2);
zoomintranformgroup2.Children.Add(rotatetransform);
videocontainer.RenderTransform = zoomintransformgroup2;
zoom++;
break;
}
}
else
{
return;
}
}
You can use the CompositeTransform class. This class combines all your used transformations and makes things easier.
Related
I've seen few questions about this problem, I tried every solution but none of them worked for my case.
My code is working; this image shows what happens when I click on Draw button.
I need to zoom on that drawing.Is it possible to code something like autocad feature "zoom/extent"?
Pen myPen = new Pen(Color.Black);
int centerpointx, centerpointy;
private void pictureBoxDraw_Paint(object sender, PaintEventArgs e)
{
centerpointx = pictureBoxDraw.Size.Width/2;
centerpointy = pictureBoxDraw.Size.Height/2;
myPen.Width = 2;
if (binary > 0)
{
var sizecrestgeo = 40;
var distancearraycrestgeo = new float[sizecrestgeo];
var elevationarraycrestgeo = new float[sizecrestgeo];
for (int i = 0; i < sizecrestgeo; i++)
{
distancearraycrestgeo[i] = float.Parse(dataGridViewCrestGeo.Rows[i].Cells[0].Value.ToString());
elevationarraycrestgeo[i] = float.Parse(dataGridViewCrestGeo.Rows[i].Cells[1].Value.ToString())*-1;
}
for (int i=0; i < sizecrestgeo-1; i++)
{
e.Graphics.DrawLine(myPen, distancearraycrestgeo[i]+centerpointx, elevationarraycrestgeo[i]+centerpointy, distancearraycrestgeo[i + 1]+centerpointx, elevationarraycrestgeo[i + 1]+centerpointy);
}
}
else
{
}
}
private void buttonDraw_Click_1(object sender, EventArgs e)
{
if (Hd > 0.0001)
{
binary = 1;
pictureBoxDraw.Invalidate();
}
else
{
MessageBox.Show("No data to draw, perform analysis first.");
}
}
private void buttoncleardraw_Click(object sender, EventArgs e)
{
binary = 0;
pictureBoxDraw.Invalidate();
}
}
This is not so hard, provided you know all the puzzle pieces.
Let's start with the obvious one:
You can scale the Graphics object to create zoomed graphics with ScaleTransform.
As I mentioned, this will include the widths of pens, font sizes and also any images you draw (though not the hatches of a HatchBrush).
You also asked about keeping the drawing 'centered'. This is a non-obvious concept: Just what is the center of your drawing surface??
When zooming (just like rotating) you always need to know the center point of the zoom (or the rotation.) By default this is the origin (0,0). I chose the center of the Panel. You may want to pick some other point..
Once you do you can move the origin of the graphics viewport to this point with TranslateTransform.
Once you have achieved all this you almost certainly will want to allow scrolling.
To do so you have two options:
You can keep AutoScroll = false and nest the canvas control inside another control, usually a Panel, which has AutoScroll = true; next make the canvas control big enough to always hold your drawing and you're done.
Or you can turn on AutoScroll for the canvas control and also set a large enough AutoScrollMinSize. If you then add the current scrolling position to the translation you are also done. Let's see this solution in action:
This is the code in the Paint event:
Size sz = panel3.ClientSize;
Point center = new Point(sz.Width / 2, sz.Height / 2);
Graphics g = e.Graphics;
// center point for testing only!
g.DrawEllipse(Pens.Orange, center.X - 3, center.Y - 3, 6, 6);
// you determine the value of the zooming!
float zoom = (trackBar1.Value+1) / 3f;
// move the scrolled center to the origon
g.TranslateTransform(center.X + panel3.AutoScrollPosition.X,
center.Y + panel3.AutoScrollPosition.Y);
// scale the graphics
g.ScaleTransform(zoom, zoom);
// draw some stuff..
using(Pen pen = new Pen(Color.Yellow, 0.1f))
for (int i = -100; i < 100; i+= 10)
g.DrawEllipse(Pens.Yellow, i-22,i-22,44,44);
A few notes:
I draw an orange circle in the center to show this point is invariant.
My coordinates go from the negative to the positive so you can see that this works nicely.
I draw with a tiny pen width; so the width of the drawing only changes once the resulting pen goes over 1 pixel. Anything draw will always be draw with 1 pxiel width, though.
I first translate and then scale so I don't have to calculate scaled poitions.
The only line in the TrackBar's Scroll event is to trigger the Paint event: panel3.Invalidate();
The only settings needed for the Panel are
panel3.AutoScroll = true;
panel3.AutoScrollMinSize = new Size(500, 500); // use the size you want to allow!
However to avoid flicker it is highly recommended to use a DoubleBuffered control, maybe a Panel subclass like this:
class DrawPanel : Panel
{
public DrawPanel() { DoubleBuffered = true; }
}
Update: Instead of a Panel, which is a Container control and not really meant to draw onto you can use a Picturebox or a Label (with Autosize=false); both have the DoubleBuffered property turned on out of the box and support drawing better than Panels do.
Graphics.ScaleTransform() is how you can zoom. Try using something like this inside your paint event handler:
e.Graphics.ScaleTransform(2.0F, 2.0F);
On iPhone and Android it is possible to zoom into a picture by sliding two fingers apart on screen. I would like to do something similar on Windows Universal Apps, but instead of zooming I want to enlarge the framework element. Is this a Manipulation Event?
Update: Yes I only want to enlarge the specific UIElement by fingers.
Currently my object is set up to translate with this event:
private void Rectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
FrameworkElement fe = sender as FrameworkElement;
if (!(fe.RenderTransform is TransformGroup))
{
TransformGroup tg = new TransformGroup();
TranslateTransform tt = new TranslateTransform();
tt.X = e.Cumulative.Translation.X;
tt.Y = e.Cumulative.Translation.Y;
ScaleTransform st = new ScaleTransform();
st.ScaleX = e.Cumulative.Scale;
st.ScaleY = e.Cumulative.Scale;
tg.Children.Add(tt);
tg.Children.Add(st);
fe.RenderTransform = tg;
}
else
{
TransformGroup tg = fe.RenderTransform as TransformGroup;
TranslateTransform tt = tg.Children[0] as TranslateTransform;
tt.X += e.Delta.Translation.X;
tt.Y += e.Delta.Translation.Y;
ScaleTransform st = tg.Children[1] as ScaleTransform;
st.ScaleX = e.Delta.Scale;
st.ScaleY = e.Delta.Scale;
}
}
This will supposedly change the Scale to Delta.Scale, but how do I get Delta.Scale to be > 0 using "Pinch and Stretch"
I am not sure what do you mean by "instead of zooming I want to enlarge the framework element"? Do you mean you only want to enlarge the specific UIElement by fingers?
Anyway, typically you can handle pointer input and use the GestureRecognizer APIs to process gestures and manipulations in a Windows Store app. You can attached related event handle to a specific UIElement.
Here is a detailed sample code for manipulating a textblock element by tapping and sliding with the help of class GestureRecognizer. Here is one more sample for reference.
Please let me know if anything not clear.
Actually i am wondering to erase an image to transparency. like i have an image on page background and another image above that. Now i want that if i erase above image by finger then lower image should be appear, simply means to say image will become transparent.i'm doing something like this but its not meet my requirements.
Your suggestions are Welcome :)
private void Canvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
currentPoint = e.GetPosition(this.canvas);
//Initialize line according to currentpoint position.
Line line = new Line()
{
X1 = currentPoint.X,
Y1 = currentPoint.Y,
X2 = oldPoint.X,
Y2 =oldPoint.Y
};
line.StrokeDashCap = PenLineCap.Round;
line.StrokeEndLineCap = PenLineCap.Round;
line.StrokeLineJoin = PenLineJoin.Round;
line.StrokeThickness = 20;
line.Stroke = new SolidColorBrush(Colors.Black) ;
////////////////////////////////
//Set color & thickness of line.
//Line add in canvas children to draw image & assign oldpoint.
this.canvas.Children.Add(line);
oldPoint = currentPoint;
}
You can do it with 3 different ways:
Using opaque overlay and UIElement.Clip property. But you need to deal with Geometry. And I'm afraid it will be very CPU cost.
Using WriteableBitmap and changing an alpha channel of image. You can do it using WriteableBitmapEx.
Using opaque overlay and UIElement.OpacityMask property. I think it's the best way to accomplish that, as you're not limited to use bitmap (so you can place any XAML control below overlay) as in the second way.
I'm writing a WPF application that displays a XAML object (it's basically a map drawn in XAML). As part of its features, it should zoom in/out and pan. The panning works fine, and the zoom zooms, but I can't quite understand how to zoom to a specific point, like my mouse cursor, for example.
This is my current code:
internal void PerformZoom(float ZoomFactor, Point ZoomCenterPoint)
{
m_originalTransform = m_canvas.RenderTransform;
float newZoomFactor = m_oldZoomFactor + ZoomFactor;
float scaleToApply = (newZoomFactor / m_oldZoomFactor);
m_totalZoom = newZoomFactor;
var st = new ScaleTransform(scaleToApply, scaleToApply);
TransformGroup tg = new TransformGroup();
tg.Children.Add(m_originalTransform);
tg.Children.Add(st);
m_canvas.RenderTransform = tg;
m_oldZoomFactor = newZoomFactor;
}
[edit] Found the solution - Just edited the CenterX / CenterY properties of the transformation and it worked like a charm.
Thanks for all your help!
[edit2] Here's a viable solution (considering the mouse position):
public partial class MainWindow
{
private float currentZoom = 1f;
private const float StepSize = .2f;
public MainWindow()
{
InitializeComponent();
}
private void MainGrid_OnMouseWheel(object sender, MouseWheelEventArgs e)
{
var pos = 1;
if (e.Delta < 0)
{
pos = -1;
}
var mousePosition = e.MouseDevice.GetPosition(MainGrid);
currentZoom += StepSize * pos;
var transform = new ScaleTransform(currentZoom, currentZoom, mousePosition.X, mousePosition.Y);
MainGrid.RenderTransform = transform;
}
}
You will have to compose your ScaleTransform with a TranslateTransform which translates your component while zooming.
The offset given by the TranslateTransform depends of the behavior you wanna have (i.e. center on mouse, center on screens center...)
I wrote in the past a behavior which you can attach to a component : It makes it zoomable (centered on mouse, reacting to mousewheel)
It's pretty dirty and not sure to be efficient (i no longer use it)... and comments are in french :-/
see the source
[edit] In fact, I remember it was to scroll and scale a Panels background. But it shouldnt be so hard to modify for applying it to any object as the transformations are the same for images and elements.
I have noticed that some applications change their controls' positions to fit themselves as much as possible in the current resolution. For example, if the window is maximized, the controls are set in such a way that the overall GUI looks balanced.
Is it possible to make or implement this functionality in Visual studio 2010 using C#?
Use Dock and Anchor properties. Here is a good article. Note that these will handle changes when maximizing/minimizing. That is a little different that if the screen resolution changes, but it will be along the same idea.
Use combinations of these to get the desired result:
Set Anchor property to None, the controls will not be resized, they only shift their position.
Set Anchor property to Top+Bottom+Left+Right, the controls will be resized but they don't change their position.
Set the Minimum Size of the form to a proper value.
Set Dock property.
Use Form Resize event to change whatever you want
I don't know how font size (label, textbox, combobox, etc.) will be affected in (1) - (4), but it can be controlled in (5).
float widthRatio = Screen.PrimaryScreen.Bounds.Width / 1280;
float heightRatio = Screen.PrimaryScreen.Bounds.Height / 800f;
SizeF scale = new SizeF(widthRatio, heightRatio);
this.Scale(scale);
foreach (Control control in this.Controls)
{
control.Font = new Font("Verdana", control.Font.SizeInPoints * heightRatio * widthRatio);
}
..and to detect a change in resolution to handle it (once you're using Docking and Anchoring like SwDevMan81 suggested) use the SystemEvents.DisplaySettingsChanged event in Microsoft.Win32.
sorry I saw the question late,
Here is an easy programmatically solution that works well on me,
Create those global variables:
float firstWidth;
float firstHeight;
after on load, fill those variables;
firstWidth = this.Size.Width;
firstHeight = this.Size.Height;
then select your form and put these code to your form's SizeChange event;
private void AnaMenu_SizeChanged(object sender, EventArgs e)
{
float size1 = this.Size.Width / firstWidth;
float size2 = this.Size.Height / firstHeight;
SizeF scale = new SizeF(size1, size2);
firstWidth = this.Size.Width;
firstHeight = this.Size.Height;
foreach (Control control in this.Controls)
{
control.Font = new Font(control.Font.FontFamily, control.Font.Size* ((size1+ size2)/2));
control.Scale(scale);
}
}
I hope this helps, it works perfect on my projects.
Here I like to use https://www.netresize.net/index.php?c=3a&id=11#buyopt. But it is paid version.
You also can get their source codes if you buy 1 Site License (Unlimited Developers).
How ever I am finding the nuget package solution.
add this code at page load do for all control or add all control in containers
int x;
Point pt = new Point();
x = Screen.PrimaryScreen.WorkingArea.Width - 1024;
x = x / 2;
pt.Y = groupBox1.Location.Y + 50;
pt.X = groupBox1.Location.X + x;
groupBox1.Location = pt;
in the form load event add this line
this.WindowState = FormWindowState.Maximized;
private void MainForm_Load( object sender, EventArgs e )
{
this.Size = Screen.PrimaryScreen.WorkingArea.Size
}
this.WindowState = FormWindowState.Maximized;