How can change position of canvas in WPF? - c#

How can change runtime position of a canvas in which dynamically I added controls like (labels, lines)?
I can zoom canvas with all controls but I can't move in another position with MouseMove, MouseUp, MouseDown.
<Canvas Name="canvas" Width="1000" Height="400"
Margin="100 0 0 50"
Background="White"
VerticalAlignment="Bottom"
HorizontalAlignment="Center"
MouseWheel="Canvas_MouseWheel"
MouseMove="Canvas_MouseMove"
MouseUp="Canvas_MouseUp"
MouseDown="Canvas_MouseDown">
<Canvas.RenderTransform>
<ScaleTransform x:Name="st" />
</Canvas.RenderTransform>
</Canvas>
I find this code in internet but for my case is not working
bool activated;
Point point;
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
activated = true;
point = Mouse.GetPosition(canvas);
Mouse.Capture(canvas);
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (activated)
{
double top = Canvas.GetTop(canGraph) + Mouse.GetPosition(canvas).Y - point.Y;
Canvas.SetTop(canvas, top);
double left = Canvas.GetLeft(canvas) + Mouse.GetPosition(canvas).X - point.X;
Canvas.SetLeft(canvas, left);
point = Mouse.GetPosition(canvas);
}
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
activated = false;
Mouse.Capture(null);
}

Edit - The previous solution that I provided was not going to work after the first move of the element without more code so here's a better one
In order to be working correctly the canvas element have to be aligned to the coordinate system of it's parent, which we achieve as we put the canvas in top left corner, if you don't put it there you have to calculate the difference yourselve.
Code behind
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
canvas.CaptureMouse();
}
Stopwatch sw = new Stopwatch();
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (canvas.IsMouseCaptured)
{
translate.X = e.GetPosition(container).X;
translate.Y = e.GetPosition(container).Y;
}
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
canvas.ReleaseMouseCapture();
}
XAML
<Grid Background="Green" x:Name="container">
<Canvas Name="canvas" Width="100" Height="100"
Margin="0 0 0 0"
Background="Purple"
VerticalAlignment="Top"
HorizontalAlignment="Left"
MouseMove="Canvas_MouseMove"
MouseDown="Canvas_MouseDown">
<StackPanel Background="White">
<TextBlock >asdasda</TextBlock>
<TextBlock >cccc</TextBlock>
<TextBlock >aaaaa</TextBlock>
<TextBlock >bbbb</TextBlock>
</StackPanel>
<Canvas.RenderTransform>
<TransformGroup>
<ScaleTransform x:Name="st" />
<TranslateTransform x:Name="translate" />
</TransformGroup>
</Canvas.RenderTransform>
</Canvas>
</Grid>
Original answer
XAML
I'd do something like this:
Add a translate transform and to keep you previous transform put it in a group
Use translate transform in order to move the canvas with positions from the mouse events
For starting point of your translations you can use coordinates in the container
Code behind:
bool activated;
Point point;
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
activated = true;
point = e.GetPosition(container);
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (activated)
{
translate.X = e.GetPosition(container).X - point.X;
translate.Y = e.GetPosition(container).Y - point.Y;
}
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
activated = false;
}
XAML
<Canvas Name="canvas" Width="100" Height="100"
Margin="0 0 0 0"
Background="Purple"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
MouseMove="Canvas_MouseMove"
MouseUp="Canvas_MouseUp"
MouseDown="Canvas_MouseDown">
<Canvas.RenderTransform>
<TransformGroup>
<ScaleTransform x:Name="st" />
<TranslateTransform x:Name="translate" />
</TransformGroup>
</Canvas.RenderTransform>
</Canvas>
</Grid>

After mouse down then again I move the canvas is start to move from first position when is been.
P.s.
I add this for more stable code , but always return back to the first position
private void Canvas_MouseLeave(object sender, MouseEventArgs e)
{
activated = false;
}

Related

Mouse Handling on Image Control of WPF

I am quite noob in WPF. I am creating a WPF application and using a EmguCV library for image Processing. I found that I can't use ImageBox in WPF. So I am using NamedWindow to show image then I decided to use Image Controlto show the image on the window. I am trying to draw the rectangle over that image but rectangle in not drawn at other place. So can anyone tell me what is wrong in the code.
Basically I want to take ROI of that image.
EDIT:-
I put the Canvas inside grid a put the Image Control inside that Canvas
**My XAML Code **
<Grid Margin="0,0,2,-1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="138*"/>
<ColumnDefinition Width="139*"/>
</Grid.ColumnDefinitions>
<Button x:Name="button" Content="Convert" Margin="139.053,432.066,0,0" Click="button_Click" Height="27.934" VerticalAlignment="Top" HorizontalAlignment="Left" Width="113.947" Grid.Column="1"/>
<Button x:Name="button1" Content="Load Palette" Margin="308,432.066,0,0" Click="button1_Click_1" Height="27.934" VerticalAlignment="Top" HorizontalAlignment="Left" Width="75" Grid.ColumnSpan="2"/>
<Button x:Name="button2" Content="Load Gray Image" Margin="48,432.066,0,0" Click="button2_Click" Height="27.934" VerticalAlignment="Top" HorizontalAlignment="Left" Width="104"/>
<Canvas x:Name="MyCanvas" Margin="81,86.5,27.245,120.5" Grid.Column="1">
<Image x:Name="image3" Height="263" Width="238"/>
</Canvas>
<Image x:Name="image1" HorizontalAlignment="Left" Height="263" Margin="10,86.5,0,0" VerticalAlignment="Top" Width="255.5"/>
<Image x:Name="image2" Grid.ColumnSpan="2" HorizontalAlignment="Left" Height="393" Margin="308,10,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
And My C# code is
private Boolean isdragging = false;
private System.Windows.Point startPoint;
private System.Windows.Point endPoint;
private System.Windows.Shapes.Rectangle rect;
private void image3_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(MyCanvas);
isdragging = true;
if(rect != null)
MyCanvas.Children.Remove(rect);
rect = new System.Windows.Shapes.Rectangle
{
Stroke = System.Windows.Media.Brushes.LightBlue,
StrokeThickness = 2
};
System.Windows.Controls.Canvas.SetLeft(rect, startPoint.X);
System.Windows.Controls.Canvas.SetTop(rect, startPoint.Y);
MyCanvas.Children.Add(rect);
}
private void image3_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
rect = null;
isdragging = false;
endPoint = e.GetPosition(MyCanvas);
}
private void image3_MouseMove(object sender, MouseEventArgs e)
{
if (isdragging == true)
{
var pos = e.GetPosition(MyCanvas);
var x = Math.Min(pos.X, startPoint.X);
var y = Math.Min(pos.Y, startPoint.Y);
var w = Math.Max(pos.X, startPoint.X) - x;
var h = Math.Max(pos.Y, startPoint.Y) - y;
rect.Width = w;
rect.Height = h;
System.Windows.Controls.Canvas.SetLeft(rect, x);
System.Windows.Controls.Canvas.SetTop(rect, y);
}
}
I am using Event Handler over the Canvas but it doesn't showing the rectangle
Thanks in Advance
Thanks Clemens, I have got the answer, Actually I haven't add the event handler to image3 Image Control that's why it is not showing the output.
<Canvas x:Name="MyCanvas" Margin="81,86.5,27.245,120.5" Grid.Column="1">
<Image x:Name="image3" Height="263" Width="238" MouseLeftButtonDown="image3_MouseLeftButtonDown" MouseLeftButtonUp="image3_MouseLeftButtonUp" MouseMove="image3_MouseMove"/>
</Canvas>

How can I force an image to overlay on the title bar of my WPF application?

I have a WPF application that has an animated .gif used to briefly direct user attention. The .gif sits just outside of the bounds of my app's window, such that it is underneath, and covered by, the title bar.
See below:
Is there a way to force it to overlay on top? It's defined in XAML like this:
<Grid>
<Image Margin="-5 -45 0 0" DockPanel.Dock="Left" gif:ImageBehavior.AnimatedSource="/Resources/jump.gif"
Width="30" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="45"/>
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
</Grid>
And it looks alright at design-time:
I tried using DockPanel instead of Grid as its container to no avail.
Lastly, is it possible to have it behave as though it was collapsed? That is, have it not take up horizontal space between the ComboBox and the Legend Label
You need to use a Popup so that it gets its own window handle. This will also make it not take up space in the layout. As an added bonus (or maybe headache) you will be able to position it with its PlacementTarget and PlacementMode properties, since it looks like that is what you are trying to do anyway.
I used a Popup and it is working quite well, but with some very little flickering.
<Window x:Name="Window1" .../>
<Grid>
<Button Content="Show" HorizontalAlignment="Left" Margin="160,114,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>
<Button Content="Hide" HorizontalAlignment="Left" Margin="265,114,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_2"/>
<Popup x:Name="Popup1" UseLayoutRounding="True" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Window1}">
<Image Source="C:\\Users\\Public\\Pictures\\Sample Pictures\\desert.jpg" Stretch="Fill" Width="75" Height="25"/>
</Popup>
</Grid>
</Window>
Code :
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Popup1.IsOpen = true;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
Popup1.IsOpen = false;
}
private void Window1_LocationChanged(object sender, EventArgs e)
{
double offset = Popup1.HorizontalOffset;
Popup1.HorizontalOffset = offset + 1;
Popup1.HorizontalOffset = offset;
}
Another approach (recommended) without Popup !
XAML
MainWindow.xaml
<Window x:Class="WpfWindow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window1" Title="MainWindow" Height="350" Width="525"
Closing="Window1_Closing" Activated="Window1_Activated" LocationChanged="Window1_LocationChanged">
<Grid x:Name="root"/>
</Window>
TitleBarWindow.xaml
<Window x:Class="WpfWindow.TitleBarWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Topmost="True"
Title="TitleBarWindow" AllowsTransparency="True" WindowStyle="None" Height="25" Width="200">
<Grid>
<Image Source="g:\\jellyfish.jpg" Stretch="Fill" HorizontalAlignment="Stretch"/>
</Grid>
</Window>
MainWindow.xaml.cs
namespace WpfWindow
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
TitleBarWindow w = new TitleBarWindow();
public MainWindow()
{
InitializeComponent();
w.ShowActivated = true;
w.Background = Brushes.Red;
}
private void Window1_LocationChanged(object sender, EventArgs e)
{
Point pt = Window1.PointToScreen(new Point(0, 0));
w.Top = pt.Y - 27;
w.Left = pt.X;
}
private void Window1_Activated(object sender, EventArgs e)
{
Point pt = Window1.PointToScreen(new Point(0, 0));
w.Top = pt.Y-27;
w.Left = pt.X;
w.Show();
}
private void Window1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
w.Close();
}
}
}
Second approach is very good, works smoothly.

MouseDragElementBehavior in UWP

I am currently porting an old game made for Windows Phone 8 in WPF/Silverlight to Universal Windows Platform. I have made letters that you can move in a canvas using MouseDragElementBehavior class. Is there any similar in UWP for this class?
There is an event called ManipulationDelta which is suggested in the comments. Here is how you can use it:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Canvas>
<TextBlock
FontSize="64"
ManipulationDelta="LetterA_ManipulationDelta"
ManipulationMode="All"
RenderTransformOrigin="0.5,0.5"
Text="A">
<TextBlock.RenderTransform>
<TranslateTransform x:Name="dragLetterA" />
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock
FontSize="64"
ManipulationDelta="LetterB_ManipulationDelta"
ManipulationMode="All"
RenderTransformOrigin="0.5,0.5"
Text="B">
<TextBlock.RenderTransform>
<TranslateTransform x:Name="dragLetterB" />
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock
FontSize="64"
ManipulationDelta="LetterC_ManipulationDelta"
ManipulationMode="All"
RenderTransformOrigin="0.5,0.5"
Text="C">
<TextBlock.RenderTransform>
<TranslateTransform x:Name="dragLetterC" />
</TextBlock.RenderTransform>
</TextBlock>
</Canvas>
</Grid>
Code behind looks like this:
private void LetterA_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
dragLetterA.X += e.Delta.Translation.X;
dragLetterA.Y += e.Delta.Translation.Y;
}
private void LetterB_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
dragLetterB.X += e.Delta.Translation.X;
dragLetterB.Y += e.Delta.Translation.Y;
}
private void LetterC_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
dragLetterC.X += e.Delta.Translation.X;
dragLetterC.Y += e.Delta.Translation.Y;
}
As simple as that.
Hope this helps.

check whether there is a focus on the elements

I have 3 textbox. How can i know which one of them has the focus?
if (TextBoxExtendedSearchName.Focus() == false &&
TextBoxExtendedSearchNomenclature.Focus() == false
&& TextBoxExtendedSearchSpecialist.Focus() == false)
{
window.Close();
}
this does not work
I Use WPF
private void TextBox1_LostFocus(object sender, RoutedEventArgs e)
{
if (!TextBox1.IsFocused && !TextBox2.IsFocused)
MessageBox.Show("Not Focus");
}
private void TextBox2_LostFocus(object sender, RoutedEventArgs e)
{
if (!TextBox1.IsFocused && !TextBox2.IsFocused)
MessageBox.Show("Not Focus");
}
this example not work
I think I understand what the problem is. it does not work when I'm doing it in the event Lost Focus.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void TextBox1_LostFocus(object sender, RoutedEventArgs e)
{
if (!TextBox1.IsFocused && !TextBox2.IsFocused)
MessageBox.Show("Not Focus");
else
MessageBox.Show("Yes Focus");
}
private void TextBox2_LostFocus(object sender, RoutedEventArgs e)
{
if (!TextBox1.IsFocused && !TextBox2.IsFocused)
MessageBox.Show("Not Focus");
else
MessageBox.Show("Yes Focus");
}
XAml
<Window x:Class="TrainWPF.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">
<Grid>
<TextBox x:Name="TextBox1" HorizontalAlignment="Left" Height="25" Margin="62,61,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="205" LostFocus="TextBox1_LostFocus"/>
<TextBox x:Name="TextBox2" HorizontalAlignment="Left" Height="23" Margin="62,145,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="205" LostFocus="TextBox2_LostFocus"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="267,249,0,0" VerticalAlignment="Top" Width="96" RenderTransformOrigin="0.5,0.5" Height="37">
<Button.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="0.397"/>
<TranslateTransform/>
</TransformGroup>
</Button.RenderTransform>
</Button>
</Grid>
</Window>
this does not work
I understand it's my logical error
try this:
//Logical focus
var focusedControl = FocusManager.GetFocusedElement(this);
//KeyBoard focus
var focusedControl = Keyboard.FocusedElement;
// dummy logic to close the window when all the three textboxes are not focused.
List<TextBox> items=new List<TextBox>();
items.Add(TextBoxExtendedSearchName);
items.Add(TextBoxExtendedSearchNomenclature);
items.Add(TextBoxExtendedSearchSpecialist);
if(!items.Any(o=>o==focusedControl))
{
window.Close();
}
You are using the wrong function. You need to use the IsFocused property to get it a Control has a focus.
See the documentation here: Link
With your code:
if (!TextBoxExtendedSearchName.IsFocused
&& !TextBoxExtendedSearchNomenclature.IsFocused
&& !TextBoxExtendedSearchSpecialist.IsFocused)
{
window.Close();
}
This will Close the window if none of them has a Focus.

Move ToolTip in WinRT

In WinRT (Windows Store Apps), I create a tooltip and set it to an element like this:
dragTip = new ToolTip();
dragTip.Content = "Test";
ToolTipService.SetToolTip(element as DependencyObject, dragTip);
dragTip.IsOpen = true;
I want to move this ToolTip as the mouse moves. Is there a way to do that? Or another alternative? I want to show a hint to the user as he/she drags an element.
Update
Here's the approach I took based on #Sajeetharan's suggestion:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}" PointerMoved="homeGrid_PointerMoved" x:Name="homeGrid">
....
<GridView x:Name="content" CanDragItems="True" DragItemsStarting="content_DragItemsStarting">
...
</GridView>
<Popup Name="DeepZoomToolTip">
<Border CornerRadius="1" Padding="1" IsHitTestVisible="False">
<TextBlock Text="Here is a tool tip" />
</Border>
</Popup>
....
</Grid>
private void content_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
DeepZoomToolTip.IsOpen = true;
}
private void homeGrid_PointerMoved(object sender, PointerRoutedEventArgs e)
{
var position = e.GetCurrentPoint(homeGrid).Position;
DeepZoomToolTip.HorizontalOffset = position.X;
DeepZoomToolTip.VerticalOffset = position.Y;
}
Notice that the tooltip will move but not when the item is being dragged.
You can do this by using a popup control , Here is the full Thread how to make tooltip move along with mouse
XAML:
<Canvas x:Name="LayoutRoot" Background="White">
<Image Source="/sam.png" MouseMove="Image_MouseMove" MouseLeave="Image_MouseLeave"/>
<Popup Name="DeepZoomToolTip">
<Border CornerRadius="1" Padding="1" IsHitTestVisible="False">
<TextBlock Text="Here is a tool tip" />
</Border>
</Popup>
</Canvas>
private void Image_MouseMove(object sender, MouseEventArgs e)
{
DeepZoomToolTip.IsOpen = true;
DeepZoomToolTip.HorizontalOffset = e.GetPosition(LayoutRoot).X;
DeepZoomToolTip.VerticalOffset = e.GetPosition(LayoutRoot).Y;
}
private void Image_MouseLeave(object sender, MouseEventArgs e)
{
DeepZoomToolTip.IsOpen = false;
}

Categories