I have a user control which moves with my finger movement.The user control has its own manipulation delta set.
My problem is , when My finger is on the user control and I am trying to move it up , I am having lag because it is not moving up with my finger.
The user control appears when I long tap on my screen , the location of the user control is whereever my finger is pressed . It moves with my finger whereever I move my finger , but once my finger goes on the user control I am not having smooth movements .
Any help would be appreciated.
The XAML is
<Page x:Name="page1"
x:Class="controlMagnifier.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:controlMagnifier"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid x:Name="ParentGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" PointerReleased="ParentGrid_OnPointerReleased" >
<Canvas x:Name="InkPresenter" Height="auto" Width="auto">
<Image Stretch="None" x:Name="image2" >
<Image.Source >
<BitmapImage UriSource="/Assets/wallpaper.jpg" />
</Image.Source>
</Image>
</Canvas>
<local:MagnifierUsercontrol x:Name="MagnifyTip" Visibility="Collapsed" ManipulationDelta="MagnifyTip_ManipulationDelta" ManipulationMode="All" >
<local:MagnifierUsercontrol.RenderTransform>
<CompositeTransform/>
</local:MagnifierUsercontrol.RenderTransform>
</local:MagnifierUsercontrol>
</Grid>
</Page>
The CS Code Is
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Shapes;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Diagnostics;
using Windows.UI.Popups;
using Windows.UI.Input;
using Windows.Storage;
using Windows.UI.Xaml.Media.Imaging;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
namespace controlMagnifier
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public const int XAxis = 105;
public const int YAxis = 270;
public Thickness margin;
public WriteableBitmap CurrentBitmapObj, CurrentCroppedImage = null;
public MainPage()
{
this.InitializeComponent();
ParentGrid.Holding += Grid_Holding;
image2.PointerMoved += InkCanvas_PointerMoved;
image2.PointerReleased += ParentGrid_OnPointerReleased;
image2.CacheMode=new BitmapCache();
StoreCrrentImage();
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Grid_Holding(object sender, HoldingRoutedEventArgs e)
{
//Point p;
try
{
Point p = e.GetPosition(ParentGrid);
double height = MagnifyTip.Height;
double width = MagnifyTip.Width;
margin = MagnifyTip.Margin;
margin.Left = p.X - XAxis;
margin.Right = p.Y - YAxis;
MagnifyTip.Margin = margin;
// MagnifyTip.Margin = new Thickness(p.X - XAxis, p.Y - YAxis, 0, 0);
MagnifyTip.Visibility = Visibility.Visible;
}
catch (Exception)
{
throw;
}
}
private void InkCanvas_PointerMoved(object sender, PointerRoutedEventArgs e)
{
try
{
PointerPoint pt = e.GetCurrentPoint(image2);
Point currentContactPt = pt.Position;
double xValue = currentContactPt.X;
double yValue = currentContactPt.Y;
// MagnifyTip.
double height = MagnifyTip.Height;
double width = MagnifyTip.Width;
MagnifyTip.image1.ImageSource = CropBitmap(currentContactPt);
MagnifyTip.Margin = new Thickness(xValue - XAxis, yValue - YAxis, 0, 0);
}
catch (Exception)
{
throw;
}
finally
{e.Handled = true;}
}
private async void StoreCrrentImage()
{
try
{
StorageFile storageFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/wallpaper.jpg", UriKind.RelativeOrAbsolute));
using (
Windows.Storage.Streams.IRandomAccessStream fileStream =
await storageFile.OpenAsync(FileAccessMode.Read))
{
BitmapImage bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
WriteableBitmap writeableBitmap =
new WriteableBitmap(bitmapImage.PixelWidth, bitmapImage.PixelHeight);
fileStream.Seek(0);
await writeableBitmap.SetSourceAsync(fileStream);
CurrentBitmapObj = writeableBitmap;
writeableBitmap.Invalidate();
}
}
catch (Exception )
{
throw;
}
finally
{}
}
/// <summary>
/// This method crops the image by accepting x and y as Arguments
/// </summary>
/// <param name="point"></param>
/// <returns>Cropped Image</returns>
private WriteableBitmap CropBitmap(Point point)
{
try
{
CurrentCroppedImage = CurrentBitmapObj.Crop(Convert.ToInt32(point.X), Convert.ToInt32(point.Y), 100, 100);
// var resized = CurrentCroppedImage.Resize(200, 300, WriteableBitmapExtensions.Interpolation.Bilinear);
}
catch (Exception)
{
throw;
}
return CurrentCroppedImage;
}
private void MagnifyTip_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
Point p;
p.X = e.Delta.Translation.X;
p.Y = e.Delta.Translation.Y;
var Dragme = (CompositeTransform)MagnifyTip.RenderTransform;
Dragme.TranslateX += p.X;
Dragme.TranslateY += p.Y;
// MagnifyTip.controlCanvas.SetValue(Canvas.SetLeft, p.X);
}
private void ParentGrid_OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
MagnifyTip.Visibility = Visibility.Collapsed;
// throw new NotImplementedException();
}
}
}
The user control looks like
If you want to avoid the lag which is intentionally implemented in ManipulationDelta to distinguish it from Tap, use PointerMove instead.
I have answered similar question here.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
My goal is : Only allowed click to remove a rectangle if there is no rectangle in front of the target rectangle.
Maybe there is a solution to get a layer level from an object ? I have found nothing about this, im new to WPF. So if some can explain the solution or the way to think about this problem.
Code xaml.cs file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace WpfApp1
{
/// <summary>
/// Logique d'interaction pour MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
DispatcherTimer gameTimer = new DispatcherTimer();
List<Rectangle> removeThis = new List<Rectangle>();
int posX;
int posY;
int width;
int rectangleVariation;
int height;
Random rand = new Random();
Brush brush;
public MainWindow()
{
InitializeComponent();
Random rand = new Random();
int nbObjects = rand.Next(15,30);
for (int i = 0; i < nbObjects; i++)
{
brush = new SolidColorBrush(Color.FromRgb((byte)rand.Next(1, 255), (byte)rand.Next(1, 255), (byte)rand.Next(1, 255)));
posX = rand.Next(15, 700);
posY = rand.Next(50, 250);
rectangleVariation = rand.Next(0, 2);
if (rectangleVariation == 0)
{
width = 200;
height = 50;
}
else
{
width = 50;
height = 200;
}
Rectangle rectangle = new Rectangle
{
Tag = "rectangle",
Height = height,
Width = width,
Stroke = Brushes.Black,
StrokeThickness = 1,
Fill = brush
};
Canvas.SetLeft(rectangle, posX);
Canvas.SetTop(rectangle, posY);
MyCanvas.Children.Add(rectangle);
}
}
private void ClickOnCanvas(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource is Rectangle)
{
Rectangle rectangle = (Rectangle)e.OriginalSource;
MyCanvas.Children.Remove(rectangle);
}
}
}
}
Code xaml file :
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Canvas Name="MyCanvas" MouseLeftButtonDown="ClickOnCanvas" Background="DarkGray">
</Canvas>
</Window>
You should first determine whether the clicked Rectangle intersects with any other Rectangle elements and if it does, you could determine whether it's in top of all of them by looking at the index in the Canvas's Children collection.
The Rect type has an IntersectsWith method that you can use. Something like this:
private void ClickOnCanvas(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource is Rectangle)
{
Rectangle clickedRectangle = (Rectangle)e.OriginalSource;
Rect clickedRect = new Rect()
{
Location = new Point(Canvas.GetLeft(clickedRectangle), Canvas.GetTop(clickedRectangle)),
Size = new Size(clickedRectangle.Width, clickedRectangle.Height)
};
for (int i = 0; i < MyCanvas.Children.Count; i++)
{
if (MyCanvas.Children[i] is Rectangle rectangle && rectangle != clickedRectangle)
{
Rect rect = new Rect()
{
Location = new Point(Canvas.GetLeft(rectangle), Canvas.GetTop(rectangle)),
Size = new Size(rectangle.Width, rectangle.Height)
};
if (clickedRect.IntersectsWith(rect) && MyCanvas.Children.IndexOf(clickedRectangle) < i)
return;
}
}
MyCanvas.Children.Remove(clickedRectangle);
}
}
Unfortunately I do not know how I adjust the axes scaling.
x and y axes should have the same scaling. As an example, you see two pictures below. Once with the blue strokes (same scaling) and once with red strokes (different scaling). How can I adjust that only the same scaling comes out (see the picture with the blue strokes). The x and y have the same distance from, for example, 0 (begin) to 10 ( end). It should not have different scaling as the picture with the red strokes. I should be able to say later that the x axis and the y axis are exactly equal to the distances of the points.
Could someone help me with the same scaling, please?
Could I also define the value range itself? Since say from -12 to + 12?
XAML
<UserControl x:Class="Vorschau.UCVorschau"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Vorschau"
xmlns:oxy="http://oxyplot.org/wpf"
mc:Ignorable="d" Height="461" Width="624">
<Canvas HorizontalAlignment="Left" Height="461" VerticalAlignment="Top" Width="624">
<Button x:Name="btGenerate" Content="Generiere Koordinaten" Canvas.Left="25" Canvas.Top="409" Click="btGenerate_Click"/>
<oxy:Plot x:Name="oxyPlot" Title="{Binding Title}" Height="350" Canvas.Left="224" Width="350" Background="#FFD1CFD0">
<oxy:Plot.Axes>
<oxy:LinearAxis Position="Bottom" MinimumPadding="0.1" MaximumPadding="0.1"/>
<oxy:LinearAxis Position="Left" MinimumPadding="0.1" MaximumPadding="0.1"/>
</oxy:Plot.Axes>
<oxy:Plot.Series>
<oxy:LineSeries x:Name="ls" ItemsSource="{Binding Points}" LineStyle="None" MarkerType="Circle" MarkerSize="5" MarkerFill="Transparent" MarkerStroke="Black" MarkerStrokeThickness="2"/>
</oxy:Plot.Series>
</oxy:Plot>
<Button x:Name="btClear" Content="Koordianten löschen" Canvas.Left="181" Canvas.Top="409" Click="btClear_Click"/>
<Button x:Name="btRead" Content="Koordianten einlesen" Canvas.Left="473" Canvas.Top="409" Click="btRead_Click"/>
<Canvas HorizontalAlignment="Left" Height="579" VerticalAlignment="Top" Width="5" Background="#FFB8B8B8" RenderTransformOrigin="0.5,0.5" Canvas.Left="311" Canvas.Top="106">
<Canvas.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="-1"/>
<SkewTransform/>
<RotateTransform Angle="90"/>
<TranslateTransform/>
</TransformGroup>
</Canvas.RenderTransform>
</Canvas>
</Canvas>
</UserControl>
UserControl
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using OxyPlot;
using OxyPlot.Series;
using System.IO;
using System.Text.RegularExpressions;
using System.Collections;
using System.Globalization;
using OxyPlot.Wpf;
using System.Diagnostics;
namespace Vorschau
{
/// <summary>
/// Interaktionslogik für UCVorschau.xaml
/// </summary>
public partial class UCVorschau : UserControl
{
public UCVorschau()
{
InitializeComponent();
try
{
DataContext = this;
this.Title = "Vorschaubild";
oxyPlot.Width = Vorschau.Properties.Settings.Default.BreiteBitmap;
oxyPlot.Height = Vorschau.Properties.Settings.Default.HoeheBitmap;
if (Vorschau.Properties.Settings.Default.MarkerTyp == 0)
{
ls.MarkerType = MarkerType.Circle;
ls.MarkerFill = System.Windows.Media.Colors.Transparent;
ls.MarkerStrokeThickness = Vorschau.Properties.Settings.Default.Kreisdurchmesser;
}
else
{
ls.MarkerType = MarkerType.Square;
ls.MarkerFill = System.Windows.Media.Colors.Black;
ls.MarkerStroke = System.Windows.Media.Colors.Black;
ls.MarkerStrokeThickness = 2;
}
}
catch (Exception error)
{
MessageBox.Show("Es trat ein unerwarteter Fehler auf. \nBitte Starten Sie die Anwendung neu." + error.ToString());
}
}
public string Title { get; set; }
public IList<DataPoint> Points { get; private set; }
/// <summary>
/// Einstelungs-Fenster wird geöffnet
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
//btEinstellung
private void btGenerate_Click(object sender, RoutedEventArgs e)
{
try
{
DateTime startZeit = DateTime.Now;
Cursor = Cursors.Wait;
if (Vorschau.Properties.Settings.Default.MarkerTyp == 0)
{
ls.MarkerType = MarkerType.Circle;
ls.MarkerFill = System.Windows.Media.Colors.Transparent;
ls.MarkerStrokeThickness = Vorschau.Properties.Settings.Default.Kreisdurchmesser;
}
else
{
ls.MarkerType = MarkerType.Square;
ls.MarkerFill = System.Windows.Media.Colors.Black;
ls.MarkerStroke = System.Windows.Media.Colors.Black;
ls.MarkerStrokeThickness = 2;
}
double zufallszahlX;
double zufallszahlY;
double XMax = 10;
double XMin = 0;
double YMax = 10;
double YMin = 0;
// Zur Erstellung des Seeds
int h = DateTime.Now.Hour;
int m = DateTime.Now.Minute;
int s = DateTime.Now.Second;
String u = h.ToString() + m.ToString() + s.ToString();
int iu = Int32.Parse(u);
Random zufall = new Random(iu);
Console.WriteLine("______________");
CultureInfo en = new CultureInfo("en-US", false); // Damit ein Punkt ist anstatt ein Komma
DataContext = this;
this.Points = new List<DataPoint>();
System.IO.File.WriteAllText(((Environment.CurrentDirectory + #"\files\koordinaten.txt")), string.Empty);
using (var fileStream = new FileStream(String.Format(Environment.CurrentDirectory + #"\files\koordinaten.txt"), FileMode.OpenOrCreate))
{
using (var streamWriter = new StreamWriter(fileStream))
{
for (int i = 0; i < Vorschau.Properties.Settings.Default.AnzahlKoordinaten; i++)
{
zufallszahlX = zufall.NextDouble() * (XMax - XMin) + XMin;
zufallszahlY = zufall.NextDouble() * (YMax - YMin) + YMin;
//Console.WriteLine("( " + zufallszahlX + " / " + zufallszahlY + " )" + " |" + i);
streamWriter.WriteLine("( " + zufallszahlX.ToString(en.NumberFormat) + " / " + zufallszahlY.ToString(en.NumberFormat) + " )" + " |" + (i + 1));
//ls.addPoint(zufallszahlX, zufallszahlY);
Points.Add(new DataPoint(zufallszahlX, zufallszahlY));
}
ls.ItemsSource = Points;
}
}
Cursor = Cursors.Arrow;
DateTime endZeit = DateTime.Now;
TimeSpan gemesseneZeit = endZeit - startZeit;
// statusbar.Text = "Gemessen Zeit für den Durchlauf: " + gemesseneZeit;
}
catch (Exception)
{
MessageBox.Show("Hoppla, da lief etwas schief.\nLeider konnten keine Koordinaten generiert werden.\nVersuchen Sie es bitte erneut.", "", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void btClear_Click(object sender, RoutedEventArgs e)
{
//botAxis.Minimum = botAxis.InternalAxis.ActualMinimum;
//botAxis.Maximum = botAxis.InternalAxis.ActualMaximum;
//lefAxis.Minimum = lefAxis.InternalAxis.ActualMinimum;
//lefAxis.Maximum = lefAxis.InternalAxis.ActualMaximum;
ls.ItemsSource = null;
}
private void btRead_Click(object sender, RoutedEventArgs e)
{
DateTime startZeit = DateTime.Now;
Cursor = Cursors.Wait;
String line;
Console.WriteLine("___________");
Console.WriteLine("Koordinaten: ");
using (System.IO.StreamReader file = new System.IO.StreamReader(Environment.CurrentDirectory + #"\files\koordinaten.txt"))
{
while ((line = file.ReadLine()) != null)
{
Regex myRegexKF = new Regex(#"^(?<koordinaet>\S\s*\S*\d+\s*\S\s*\S*\d+\s*\S)\s*\S\d+", RegexOptions.IgnoreCase);
Match matchSuccess = myRegexKF.Match(line);
if (matchSuccess.Success)
{
String koordinaten = matchSuccess.Groups["koordinate"].Value;
System.Console.WriteLine(koordinaten);
}
}
}
System.Console.ReadLine();
Cursor = Cursors.Arrow;
DateTime endZeit = DateTime.Now;
TimeSpan gemesseneZeit = endZeit - startZeit;
}
}
}
in modern OxyPlot 2.0+ you should set
plotModel.PlotType = PlotType.Cartesian;
and it will constraint the proportions, but minor zooming and padding issues might appear.
Set the MajorStep in both axis to be the same:
<oxy:Plot.Axes>
<oxy:LinearAxis ... MajorStep="1"/>
<oxy:LinearAxis ... MajorStep="1"/>
</oxy:Plot.Axes>
Note that there are other similar properties that you might want to control: MinorStep, MajorTickSize and MinorTickSize.
Also note that labels are put on Major Ticks.
I think original documentation will solve your problem.
1) To set axis Maximum\Minimum set same named properties at you Xaml for LinearAxis.
2) To define specific axis mark steps use Major/minor intervals of LinearAxis
I'm trying to create a Paint Application in WPF using Canvas. I want to increase the thickness of my shape while drawing so I try increasing StrokeThickness.
This is how I want it to be:
And this is what I get:
As you can see the outline only extends inside the boundary. How can I make it extends on both side?
Here is my code:
In MouseDown Event:
Rectangle rect = new Rectangle();
rect.Stroke = _color;
rect.StrokeThickness = _size;
Canvas.SetLeft(rect, _startPoint.X);
Canvas.SetTop(rect, _startPoint.Y);
cv_PaintBoard.Children.Add(rect);
isDrawing = true;
In MouseMove Event:
if (isDrawing == true && e.LeftButton == MouseButtonState.Pressed)
{
Canvas canvas = (Canvas)sender;
Rectangle rect = canvas.Children.OfType<Rectangle>().LastOrDefault();
if (rect != null)
{
Point endPoint = e.GetPosition((IInputElement)sender);
Point startPoint = new Point(
Math.Min(endPoint.X, _startPoint.X),
Math.Min(endPoint.Y, _startPoint.Y)
);
rect.Width = Math.Max(endPoint.X, _startPoint.X) - startPoint.X;
rect.Height = Math.Max(endPoint.Y, _startPoint.Y) - startPoint.Y;
Canvas.SetLeft(rect, startPoint.X);
Canvas.SetTop(rect, startPoint.Y);
}
}
You need to update width/height and left/top too for your specific needs.
The below example demonstrates your needs. If it is ok with you, let me know.
MainWindow.xaml
<Window x:Class="WpfDrawing.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="447.368" Width="606.579">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="13*"/>
<RowDefinition Height="7*"/>
</Grid.RowDefinitions>
<Canvas Grid.RowSpan="1">
<Rectangle x:Name="Rect1" Fill="Transparent" HorizontalAlignment="Left" Height="70" Canvas.Left="248" Canvas.Top="104" Stroke="Black" Width="94" Opacity="0.5" />
<Rectangle x:Name="Rect2" Fill="#FF52E03C" HorizontalAlignment="Left" Height="70" Canvas.Left="248" Canvas.Top="104" Stroke="Black" Width="94" Opacity="0.5" />
</Canvas>
<TextBox x:Name="tbThickness" HorizontalAlignment="Left" Height="23" Margin="84,27,0,0" Grid.Row="1" TextWrapping="Wrap" Text="5" VerticalAlignment="Top" Width="120"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="237,28,0,0" Grid.Row="1" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfDrawing
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
double designWidth;
double designHeight;
double designLeft, designTop;
public MainWindow()
{
InitializeComponent();
designWidth = Rect2.Width;
designHeight = Rect2.Height;
designLeft = Canvas.GetLeft(Rect2);
designTop = Canvas.GetTop(Rect2);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Rect2.StrokeThickness = double.Parse(tbThickness.Text);
Canvas.SetLeft(Rect2,designLeft - (Rect2.StrokeThickness / 2));
Canvas.SetTop(Rect2, designTop - (Rect2.StrokeThickness / 2));
Rect2.Width = designWidth + Rect2.StrokeThickness;
Rect2.Height = designHeight + Rect2.StrokeThickness;
}
}
}
There is no need to do any calculations to correct the size of a rectangle by half of its stroke thickness.
Just use Path controls with RectangleGeometries instead of Rectangle controls:
private Brush stroke = Brushes.Red;
private double strokeThickness = 10;
private Path currentPath;
private Point startPoint;
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
var canvas = (Canvas)sender;
if (canvas.CaptureMouse())
{
startPoint = e.GetPosition(canvas);
currentPath = new Path
{
Data = new RectangleGeometry(new Rect(startPoint, startPoint)),
Stroke = stroke,
StrokeThickness = strokeThickness
};
canvas.Children.Add(currentPath);
}
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (currentPath != null)
{
((RectangleGeometry)currentPath.Data).Rect
= new Rect(startPoint, e.GetPosition((UIElement)sender));
}
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
((UIElement)sender).ReleaseMouseCapture();
currentPath = null;
}
This is my first time posting, so be easy on me...
There are definitely posts that show how to connect lines to blocks, but this one is slightly different. The grids are placed on the canvas dynamically. I want a line to connect the grid from where the button is pressed to the new grid that's placed on the canvas. However the below code doesn't work. I've struggled with this one for a very long time.
Solely by accident I discovered a Messagebox thrown in the button event handler will allow it to work. I figured this was from threads running at different times, but after messing with task.delay/thread.sleep/async/await I can't find the solution.
I'm using custom classes because this is a stripped down version of the larger program, I wanted to have similar functionality in my example to reflect possible errors but leave out the unnecessary pieces.
I'm using this as a last resort, thank you in advance for any help you can provide. First the CS code
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Grid1 g = myCanvas.CreateGrid();
ContentControl1 cc = myCanvas.CreateCC();
Button1 b = myCanvas.CreateButton1();
Grid1.SetColumn(cc, 0);
Grid1.SetRow(cc, 0);
Grid1.SetColumn(b, 1);
Grid1.SetRow(b, 1);
g.Children.Add(cc);
g.Children.Add(b);
Canvas1.SetLeft(g, 500);
Canvas1.SetTop(g, 5);
myCanvas.Children.Add(g);
}
}
public class Button1 : Button
{
protected override void OnClick()
{
Grid1 old_g = (Grid1)VisualTreeHelper.GetParent(this as DependencyObject);
Canvas1 cnv = (Canvas1)VisualTreeHelper.GetParent(old_g as DependencyObject);
Grid1 g = cnv.CreateGrid();
ContentControl1 cc = cnv.CreateCC();
Button1 b = cnv.CreateButton1();
Grid1.SetColumn(cc, 0);
Grid1.SetRow(cc, 0);
Grid1.SetColumn(b, 1);
Grid1.SetRow(b, 1);
g.Children.Add(cc);
g.Children.Add(b);
Canvas1.SetLeft(g, 500);
Canvas1.SetTop(g, cnv.Children.Count * 120);
cnv.Children.Add(g);
cnv.ConnectGrids(old_g, g);
}
}
public class Canvas1 : Canvas
{
public Grid1 CreateGrid()
{
Grid1 g = new Grid1() { Width = 100, Height = 20, Background = Brushes.White };
g.HorizontalAlignment = HorizontalAlignment.Center;
g.VerticalAlignment = VerticalAlignment.Center;
g.ShowGridLines = false;
ColumnDefinition colDef1 = new ColumnDefinition();
ColumnDefinition colDef2 = new ColumnDefinition() { Width = new GridLength(20) };
g.ColumnDefinitions.Add(colDef1);
g.ColumnDefinitions.Add(colDef2);
RowDefinition rowDef1 = new RowDefinition();
g.RowDefinitions.Add(rowDef1);
return g;
}
public ContentControl1 CreateCC()
{
ContentControl1 cc = new ContentControl1()
{
VerticalContentAlignment = VerticalAlignment.Stretch,
HorizontalContentAlignment = HorizontalAlignment.Stretch,
BorderBrush = Brushes.BlueViolet,
};
return cc;
}
public Button1 CreateButton1()
{
Button1 b = new Button1()
{
VerticalContentAlignment = VerticalAlignment.Stretch,
HorizontalContentAlignment = HorizontalAlignment.Stretch,
BorderBrush = Brushes.Red
};
return b;
}
public void ConnectGrids(Grid1 g1, Grid1 g2)
{
Canvas1 cnv = (Canvas1)VisualTreeHelper.GetParent(g1 as DependencyObject);
Transform transform1 = (Transform)g1.TransformToVisual(cnv as Visual);
Transform transform2 = (Transform)g2.TransformToVisual(cnv as Visual);
Point StartPoint1 = transform1.Transform(new Point(g1.Width, g1.Height / 2.0));
Point EndPoint1 = transform2.Transform(new Point(g2.Width, g2.Height / 2.0));
var lineGeometry = new LineGeometry()
{
StartPoint = StartPoint1,
EndPoint = EndPoint1
};
var path = new Path()
{
Data = lineGeometry,
Stroke = new SolidColorBrush(Colors.Black),
};
cnv.Children.Add(path);
}
}
public class ContentControl1 : ContentControl
{
}
public class Grid1 : Grid
{
}
}
then the xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local ="clr-namespace:WpfApplication1"
Title="MainWindow" Height="1000" Width="1000">
<DockPanel>
<Button DockPanel.Dock="Top" Width="100" Height="20" Content="Start" Click="Button_Click"/>
<ScrollViewer HorizontalScrollBarVisibility="Visible" Width="901" x:Name="_scrollViewer" Margin="0,5,0,25">
<local:Canvas1 Background="Gray" Height="1000" Width="1000" x:Name="myCanvas"/>
</ScrollViewer>
</DockPanel>
</Window>
How can I successfully connect the grid with the path?
I love that I solved this/hate that I have to answer my own dumb question...
Sooo simple. UpdateLayout(). The objects don't change location until it has been rendered, so the line was going to its old location.
I'm very new to WPF and I'm trying to create a picture cropping application. The program has a rectangle that can be dragged to crop the picture (like in Microsoft Paint). The way its set up is that both image and canvas which holds the rectangle are children of grid container. Grid has events for mousemove, mouseleftbuttondown and up to calculate the cropped image. My program is cropping the image fine but the problem occurs when the window is maximized which throws an exception error below:
An unhandled exception of type 'System.ArgumentException' occurred in PresentationCore.dll
Additional information: Value does not fall within the expected range.
This exception is caused by a line in my Go_Click method:
BitmapSource bs = new CroppedBitmap(LoadedImage.Source as BitmapSource, rcFrom);
I stepped into the program and found out that at first it was caused by setting the width and height of Image (LoadedImage.Width and LoadedImage.Height) to auto or NAN. This makes the value NAN which mess up the calculation and throws of the exception. I changed it to ActualWidth (LoadedImage.ActualWidth and ActualHeight) and I only got it work partially since it still throws an exception whenever I crop the image while window is maximized.
Below is source code for my project.
XAML:
<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">
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<GroupBox Header="Loaded Image:" Grid.Column="0">
<Grid x:Name="LoadedImage" MouseLeftButtonDown="image1_MouseLeftButtonDown" MouseMove="image1_MouseMove" MouseLeftButtonUp="image1_MouseLeftButtonUp" ShowGridLines="True">
<Image x:Name="loaded" Margin="10" Stretch="Fill"/>
<Canvas x:Name="BackPanel" Margin="10">
<Rectangle x:Name="selectionRectangle" Stroke="LightBlue" Fill="#220000FF" Visibility="Collapsed"/>
</Canvas>
</Grid>
</GroupBox>
<StackPanel Grid.Column="1" x:Name="MyPanel" HorizontalAlignment="Left" Orientation="Vertical" Height="340" Width="262">
<GroupBox x:Name="Box2" Header="Preview Box:">
<Image x:Name="PreviewImage" MaxWidth="240" MaxHeight="240" Stretch="Fill" MinWidth="240" MinHeight="240"/>
</GroupBox>
<StackPanel Height="61" Orientation="Horizontal" HorizontalAlignment="Center">
<Button MinWidth="93" Height="32" Click="Import_Click">Import</Button>
<Button Name="Crop" MinWidth="93" Height="32" Margin="10,0,0,0" Click="Go_Click">Crop</Button>
</StackPanel>
</StackPanel>
</Grid>
And this is the code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Win32;
using System.IO;
namespace WpfApplication2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private bool isDragging = false;
private Point anchorPoint = new Point();
public MainWindow()
{
InitializeComponent();
}
//Import Button event handler which opens an open file dialog
//to choose an image file. If the return value from ShowDialog
//is true (user choose image and click's OK)it will store the image to file,
//else it would exit open file dialog.
private void Go_Click(object sender, RoutedEventArgs e)
{
if (loaded.Source != null)
{
Rect rect1 = new Rect(Canvas.GetLeft(selectionRectangle), Canvas.GetTop(selectionRectangle), selectionRectangle.Width, selectionRectangle.Height);
Int32Rect rcFrom = new Int32Rect();
rcFrom.X = (int)((rect1.X) * (loaded.Source.Width) / `enter code here`(loaded.ActualWidth));
rcFrom.Y = (int)((rect1.Y) * (loaded.Source.Height) / (loaded.ActualHeight));
rcFrom.Width = (int)((rect1.Width) * (loaded.Source.Width) / (loaded.ActualWidth));
rcFrom.Height = (int)((rect1.Height) * (loaded.Source.Height) / (loaded.ActualHeight));
BitmapSource bs = new CroppedBitmap(loaded.Source as BitmapSource, rcFrom);
PreviewImage.Source = bs;
}
}
private void image1_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
double x = e.GetPosition(BackPanel).X;
double y = e.GetPosition(BackPanel).Y;
selectionRectangle.SetValue(Canvas.LeftProperty, Math.Min(x, anchorPoint.X));
selectionRectangle.SetValue(Canvas.TopProperty, Math.Min(y, anchorPoint.Y));
selectionRectangle.Width = Math.Abs(x - anchorPoint.X);
selectionRectangle.Height = Math.Abs(y - anchorPoint.Y);
if (selectionRectangle.Visibility != Visibility.Visible)
selectionRectangle.Visibility = Visibility.Visible;
}
}
private void image1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (isDragging == false)
{
anchorPoint.X = e.GetPosition(BackPanel).X;
anchorPoint.Y = e.GetPosition(BackPanel).Y;
isDragging = true;
}
}
private void image1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (isDragging)
{
isDragging = false;
if (selectionRectangle.Width > 0)
{
Crop.Visibility = System.Windows.Visibility.Visible;
Crop.IsEnabled = true;
}
if (selectionRectangle.Visibility != Visibility.Visible)
selectionRectangle.Visibility = Visibility.Visible;
}
}
private void RestRect()
{
selectionRectangle.Visibility = Visibility.Collapsed;
isDragging = false;
}
private void Import_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.FileName = "Picture";
dlg.Filter = "All Pictures (*.jpeg)|*.jpg";
if (dlg.ShowDialog() == true)
{
loaded.Source = new BitmapImage(new Uri(dlg.FileName));
}
}
}
}
Like I said i'm new to programming WPF and I apologize if the way i have my code written may not be the best. But any advise would help on how I should handle this issue.
Thanks in advance.
You need to get LoadedImage position relative to GridLoadedImage, and use it when creating crop:
private void Go_Click(object sender, RoutedEventArgs e)
{
if (LoadedImage.Source != null)
{
var imagePosition = loaded.TransformToAncestor(LoadedImage).Transform(new Point(0, 0));
Rect rect1 = new Rect(Math.Max(Canvas.GetLeft(selectionRectangle) - imagePosition.X, 0), Canvas.GetTop(selectionRectangle), selectionRectangle.Width, selectionRectangle.Height);
Int32Rect rcFrom = new Int32Rect();
rcFrom.X = (int)((rect1.X) * (LoadedImage.Source.Width) / (LoadedImage.ActualWidth));
rcFrom.Y = (int)((rect1.Y) * (LoadedImage.Source.Height) / (LoadedImage.ActualHeight));
rcFrom.Width = (int)((rect1.Width) * (LoadedImage.Source.Width) / (LoadedImage.ActualWidth));
rcFrom.Height = (int)((rect1.Height) * (LoadedImage.Source.Height) / (LoadedImage.ActualHeight));
BitmapSource bs = new CroppedBitmap(LoadedImage.Source as BitmapSource, rcFrom);
PreviewImage.Source = bs;
}
}