I'm currently trying out WPF for the first time, because I have used WinForms before. I started with a little practice and wanted to create a program which draws a line to wherever you click on a canvas. I programatically added the line to the canvas, but it seems that it doesn't draw it. The lines become children of the canvas though.
C# Code
private ArrayList arl = new ArrayList();
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
drawArea.Children.Clear();
arl.Add(Mouse.GetPosition(drawArea));
Point[] points = new Point[arl.Count];
for (int i = 0; i < arl.Count; i++)
points[i] = (Point)arl[i];
Line[] lines = new Line[points.Length - 1];
if(lines.Count() > 0)
{
for (int i = 0; i < lines.Length; i++)
{
lines[i] = new Line();
lines[i].Stroke = SystemColors.WindowFrameBrush;
lines[i].X1 = points[i + 1].X;
lines[i].X2 = points[i].X;
lines[i].Y1 = points[i + 1].Y;
lines[i].Y2 = points[i].Y;
}
foreach (var item in lines)
drawArea.Children.Add(item);
}
}
XAML
<Window x:Class="WPFttest.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:WPFttest"
mc:Ignorable="d"
Title="MainWindow" Height="362" Width="525" MouseDown="Window_MouseDown" BorderBrush="Red" ResizeMode="NoResize" KeyDown="Window_KeyDown" WindowStyle="None">
<Grid x:Name="mainGrid" HorizontalAlignment="Left" Height="362" VerticalAlignment="Top" Width="525" OpacityMask="#00000000">
<Canvas x:Name="drawArea" HorizontalAlignment="Left" Height="312" Margin="0,50,0,0" VerticalAlignment="Top" Width="525" Background="White" MouseDown="Canvas_MouseDown">
</Canvas>
<Grid HorizontalAlignment="Left" Height="50" VerticalAlignment="Top" Width="525" MouseDown="Grid_MouseDown_1" OpacityMask="#00000000" Background="#00000000"/>
</Grid>
Related
I'm making a simple program, where I can drag and drop elements to the grid, but their position depends on the particular column and row. So I tried to use PreviewLeftButtonUp event to find out the position, that is pointed with cursor, but it fires after Drop event and elements are placed in the wrong position.
XAML:
<Window x:Class="Pazzles.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:Pazzles"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Menu x:Name="menu" VerticalAlignment="Top" Grid.Row="0">
<MenuItem Header="Розбити зображення">
<MenuItem Header="Відкрити" Click="OpenImage_Click"/>
<MenuItem Header="Розрізати зображення" Click="CutImage_Click"/>
</MenuItem>
<MenuItem Header="Зібрати пазл" Click ="OpenCatalog_Click">
</MenuItem>
</Menu>
<Grid Grid.Row="1" Name="layout">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollViewer>
<StackPanel x:Name="stackPanel" Width="150" Grid.Column="0"/>
</ScrollViewer>
<GridSplitter Grid.Column="1" ShowsPreview="False" Width="3" VerticalAlignment="Stretch" HorizontalAlignment="Center"/>
<Grid x:Name="grid" Background="Transparent" Grid.Column="2" ShowGridLines="True" AllowDrop="True" PreviewMouseLeftButtonUp="grid_MouseMove" Drop ="grid_Drop">
</Grid>
</Grid>
</Grid>
</Window>
C# :
private void img_MouseDown(object sender, MouseButtonEventArgs e)
{
Image img = (Image)sender;
DataObject dataObject = new DataObject(typeof(ImageSource), img.Source);
DragDrop.DoDragDrop(img, dataObject, DragDropEffects.All);
}
private void grid_MouseMove(object sender, MouseEventArgs e)
{
double y = e.GetPosition(grid).Y;
double start = 0.0;
row = 0;
foreach (RowDefinition rd in grid.RowDefinitions)
{
start += rd.ActualHeight;
if (y < start)
{
break;
}
row++;
}
double x = e.GetPosition(grid).X;
start = 0.0;
col = 0;
foreach (ColumnDefinition cd in grid.ColumnDefinitions)
{
start += cd.ActualWidth;
if (x < start)
{
break;
}
col++;
}
}
private void grid_Drop(object sender, DragEventArgs e)
{
Image imageControl = new Image { Stretch = Stretch.Fill };
if ((e.Data.GetData(typeof(ImageSource)) != null))
{
ImageSource image = e.Data.GetData(typeof(ImageSource)) as ImageSource;
imageControl = new Image() { Stretch = Stretch.Fill, Source = image };
}
else
{
if ((e.Data.GetData(typeof(Image)) != null))
{
Image image = e.Data.GetData(typeof(Image)) as Image;
imageControl = image;
if (((Grid)sender).Children.Contains(image))
{
((Grid)sender).Children.Remove(image);
}
}
}
Grid.SetColumn(imageControl, col);
Grid.SetRow(imageControl, row);
((Grid)sender).Children.Add(imageControl);
}
you can get the position in the grid_Drop method using Mouse.GetPosition()like this:
private void grid_Drop(object sender, DragEventArgs e)
{
Point location = Mouse.GetPosition(grid);
//do calculation from mouse_move method to get the col and row
Image imageControl = new Image { Stretch = Stretch.Fill};
if ((e.Data.GetData(typeof(ImageSource)) != null))
{
ImageSource image = e.Data.GetData(typeof(ImageSource)) as ImageSource;
imageControl = new Image() { Stretch = Stretch.Fill, Source = image };
}
else
{
if ((e.Data.GetData(typeof(Image)) != null))
{
Image image = e.Data.GetData(typeof(Image)) as Image;
imageControl = image;
if (((Grid)sender).Children.Contains(image))
{
((Grid)sender).Children.Remove(image);
}
}
}
Grid.SetColumn(imageControl, col);
Grid.SetRow(imageControl, row);
((Grid)sender).Children.Add(imageControl);
}
I want to write a WPF program wherein I want to print a specific part of the program/window. I only want the canvas to be printed.
Unfortunately the whole window gets printed all the time, but I only want the canvas to be printed.
Here is an example of the layout:
Here is my code:
public partial class MainWindow : Window
{
string name;
public MainWindow()
{
InitializeComponent();
}
private void Text(double x, double y, string text)
{
canvasPrintExample.Children.Clear();
TextBlock textBlock = new TextBlock();
textBlock.Text = text;
textBlock.Foreground = new SolidColorBrush(Colors.Black);
Canvas.SetLeft(textBlock, x);
Canvas.SetTop(textBlock, y);
canvasPrintExample.Children.Add(textBlock);
}
private void tbxClientInfoName_TextChanged(object sender, TextChangedEventArgs e)
{
clientInfoName = tbxClientInfoName.Text;
Text(0, 0, name);
}
private void btnPrintCanvas_Click(object sender, RoutedEventArgs e)
{
PrintDialog prnt = new PrintDialog();
if (prnt.ShowDialog() == true)
{
Size pageSize = new Size(prnt.PrintableAreaWidth, prnt.PrintableAreaHeight);
canvasPrintExample.Measure(pageSize);
canvasPrintExample.Arrange(new Rect(0, 0, pageSize.Width, pageSize.Height));
prnt.PrintVisual(canvasPrintExample, "Print");
}
this.Close();
}
}
I've tried changing this line in 'btnPrintCanvas_Click'
Size pageSize = new Size(canvasPrintExample.Width, canvasPrintExample.Height);
And I've tried hardcode the size:
Size pageSize = new Size(200, 400);
But nothing changes. All I get is this .pdf print:
Edit - added .xaml
<Window x:Class="Test.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:Factv001"
mc:Ignorable="d"
Title="MainWindow" Height="810" Width="1010" Background="LightGray">
<Grid>
<Canvas Name="canvasPrintExample" HorizontalAlignment="Left" Height="750" Margin="452,10,0,0" VerticalAlignment="Top" Width="530.3" Background="White"/>
<TextBox Name="tbxClientInfoName" HorizontalAlignment="Left" Height="23" Margin="10,31,0,0" TextWrapping="Wrap" Text="Name" VerticalAlignment="Top" Width="225" TextChanged="tbxClientInfoName_TextChanged"/>
<Button x:Name="btnPrintCanvas" Content="Print" HorizontalAlignment="Left" Margin="167,682,0,0" VerticalAlignment="Top" Width="75" Click="btnPrintCanvas_Click"/>
</Grid>
I have this peculiar problem. I am having a user control . I am making an app for Windows 8.1 where I would choose an image from my Picture gallery. The image would open in my app with Stretch is Uniform and Horizontal And vertical alignment to center.
My user control will appear where I tap on the image. Now the problem is , when the image Stretch was none , I was able to magnify the correct region (around my click) , but now when I make it Stretch to Uniform and Set the horizontal and vertical Alignment to Center , I am getting other pixel information in my user control.
I want to know how to fix it.Any how , the images can be of 2*Full HD also or they can be HD or even less.
Secondly , I want to know the boundaries of the image . With boundaries I want to say that , my user control shouldnt go above the boundaries of the image .
How to implement that. If my code is needed , I would paste it , If required.
Have this video for reference . This is what I have to develop ! I have the user control ready and I am getting exact pixels for Stretch=NONE , and no Horizontal And Vertical Alignment set.
This is my code for my app
I believe the issue is with how you use the control, rather than the image. If you avoid doing the bitmap cropping and replacing, it would speed up dramatically and likely work for all stretch types.
I've modified the source to show this - removing the Cropping completely. If you need cropping for other reasons, you should consider using the unsafe keyword (and property setting to allow) in order to dramatically speed up its use.
Also, to avoid the lagging/jumping upward, I added IsHitTestVisible="False" so that your delta wouldn't be interrupted by hovering over your image.
I see you have the 45-degree code already - since it wasn't in your source, I only added an example of 90 degree rotation when you get to the sides - so you can see how to set a RenderTransformOrigin point.
MainPage.xaml:
<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="Uniform" x:Name="image2" >
<Image.Source >
<BitmapImage UriSource="/Assets/wallpaper.jpg" />
</Image.Source>
</Image>
</Canvas>
<local:MagnifierUsercontrol x:Name="MagnifyTip" Visibility="Collapsed" ManipulationMode="All"
IsHitTestVisible="False" Height="227" Width="171"
VerticalContentAlignment="Bottom" HorizontalContentAlignment="Center">
</local:MagnifierUsercontrol>
</Grid>
</Page>
MainPage.xaml.cs:
using System;
using Windows.Foundation;
using Windows.Storage;
using Windows.UI.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
namespace controlMagnifier
{
public sealed partial class MainPage : Page
{
public const int XAxis = 200;
public const int YAxis = 435;
private readonly RotateTransform myRotateTransform = new RotateTransform {CenterX = 0.5, CenterY = 1};
private readonly ScaleTransform myScaleTransform = new ScaleTransform {ScaleX = 1, ScaleY = 1};
private readonly TransformGroup myTransformGroup = new TransformGroup();
private readonly TranslateTransform myTranslateTransform = new TranslateTransform();
public WriteableBitmap CurrentBitmapObj, CurrentCroppedImage = null;
public Point currentContactPt, GridPoint;
public Thickness margin;
public PointerPoint pt;
public double xValue, yValue;
public MainPage()
{
InitializeComponent();
ParentGrid.Holding += Grid_Holding;
image2.PointerMoved += InkCanvas_PointerMoved;
image2.PointerReleased += ParentGrid_OnPointerReleased;
margin = MagnifyTip.Margin;
image2.CacheMode = new BitmapCache();
myTransformGroup.Children.Add(myScaleTransform);
myTransformGroup.Children.Add(myRotateTransform);
myTransformGroup.Children.Add(myTranslateTransform);
MagnifyTip.RenderTransformOrigin = new Point(0.5, 1);
MagnifyTip.RenderTransform = myTransformGroup;
}
private void Grid_Holding(object sender, HoldingRoutedEventArgs e)
{
try
{
GridPoint = e.GetPosition(image2);
myTranslateTransform.X = xValue - XAxis;
myTranslateTransform.Y = yValue - YAxis;
MagnifyTip.RenderTransform = myTransformGroup;
MagnifyTip.Visibility = Visibility.Visible;
}
catch (Exception)
{
throw;
}
}
private void InkCanvas_PointerMoved(object sender, PointerRoutedEventArgs e)
{
try
{
pt = e.GetCurrentPoint(image2);
currentContactPt = pt.Position;
xValue = currentContactPt.X;
yValue = currentContactPt.Y;
if (xValue > 300)
{
myRotateTransform.Angle = -90;
}
else if (xValue < 100)
{
myRotateTransform.Angle = 90;
}
else
{
myRotateTransform.Angle = 0;
}
MagnifyTip.RenderTransform = myRotateTransform;
myTranslateTransform.X = xValue - XAxis;
myTranslateTransform.Y = yValue - YAxis;
MagnifyTip.RenderTransform = myTransformGroup;
}
catch (Exception)
{
throw;
}
finally
{
e.Handled = true;
}
}
private async void StoreCrrentImage()
{
try
{
var storageFile =
await
StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/wallpaper.jpg",
UriKind.RelativeOrAbsolute));
using (
var fileStream =
await storageFile.OpenAsync(FileAccessMode.Read))
{
var bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
var writeableBitmap =
new WriteableBitmap(bitmapImage.PixelWidth, bitmapImage.PixelHeight);
fileStream.Seek(0);
await writeableBitmap.SetSourceAsync(fileStream);
CurrentBitmapObj = writeableBitmap;
writeableBitmap.Invalidate();
}
}
catch (Exception)
{
// Graphics g=new Graphics();
throw;
}
finally
{
}
}
private void ParentGrid_OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
MagnifyTip.Visibility = Visibility.Collapsed;
}
}
}
MagnifierUsercontrol.xaml:
<UserControl
x:Class="controlMagnifier.MagnifierUsercontrol"
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" Height="227" Width="171">
<Canvas x:Name="controlCanvas" x:FieldModifier="public" Height="Auto" Width="Auto" >
<Grid Height="227" Width="171" HorizontalAlignment="Center" Canvas.Left="0" Canvas.Top="0">
<Border x:FieldModifier="public" x:Name="imgBorder" Width="150" CornerRadius="50,50,50,50" Margin="13,25,13,97">
<Border.Background>
<ImageBrush x:FieldModifier="public" x:Name="image1" />
</Border.Background>
</Border>
<TextBlock x:Name="txtreading" Height="30" Width="80" Margin="0,-145,0,0" FontWeight="Bold" Foreground="Red" FontSize="20" Text="ABC" TextAlignment="Center" />
<!--<Image Height="120" Width="150" Margin="0,-50,0,0" Source="Assets/SmallLogo.scale-100.png" ></Image>-->
<Path x:Name="MagnifyTip" Data="M25.533,0C15.457,0,7.262,8.199,7.262,18.271c0,9.461,13.676,19.698,17.63,32.338 c0.085,0.273,0.34,0.459,0.626,0.457c0.287-0.004,0.538-0.192,0.619-0.467c3.836-12.951,17.666-22.856,17.667-32.33 C43.803,8.199,35.607,0,25.533,0z M25.533,32.131c-7.9,0-14.328-6.429-14.328-14.328c0-7.9,6.428-14.328,14.328-14.328 c7.898,0,14.327,6.428,14.327,14.328C39.86,25.702,33.431,32.131,25.533,32.131z" Fill="#FFF4F4F5" Stretch="Fill" Stroke="Black" UseLayoutRounding="False" Height="227" Width="171" />
</Grid>
</Canvas>
</UserControl>
Let me know if this helps or if there is further toward your specific question.
How can I restrict panning for canvas when mouse-pointer comes out of border.. My panning code is below:
private Point origin;
private Point start;
void Path_MouseMove(object sender, MouseEventArgs e)
{
if (rBtnPanning.IsChecked.Value)
{
if (!((Path)sender).IsMouseCaptured) return;
Point p = e.MouseDevice.GetPosition(clipBorder);
Matrix m = CanvasPanel.RenderTransform.Value;
m.OffsetX = origin.X + (p.X - start.X);
m.OffsetY = origin.Y + (p.Y - start.Y);
CanvasPanel.RenderTransform = new MatrixTransform(m);
}
}
void path_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (((Path)sender).IsMouseCaptured) return;
((Path)sender).CaptureMouse();
start = e.GetPosition(clipBorder);
origin.X = CanvasPanel.RenderTransform.Value.OffsetX;
origin.Y = CanvasPanel.RenderTransform.Value.OffsetY;
}
void path_MouseLeftBtnUp(object sender, MouseButtonEventArgs e)
{
((Path)sender).ReleaseMouseCapture();
}
Xaml code is below added:
As it has Canvas between Border. I need to restrict the panning, that it shouldn't move when I hold MouseLeftDown and drag out of border.
<Window x:Class="DummyTestWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="1000" Width="1000" Background="Bisque">
<Grid Height="1000" Width="1000" x:Name="grid">
<Border x:Name="clipBorder" Height="810" Width="810" BorderThickness="2" BorderBrush="Black" ClipToBounds="True">
<Canvas x:Name="CanvasPanel" Height="800" Width="800" Background="Transparent" >
</Canvas>
</Border>
<Grid>
<Button Content="Original Size" Height="23" Name="btn_Original" Width="75" Click="btn_Original_Click" Margin="4,4,921,973" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="4,59,0,0" Name="txtNoOfZones" VerticalAlignment="Top" Width="120" MaxLength="2" PreviewTextInput="txtNoOfZones_PreviewTextInput" />
<Label Content="Enter a number below for No. of Zones" Height="28" HorizontalAlignment="Left" Margin="4,33,0,0" Name="label1" VerticalAlignment="Top" Width="220" FontFamily="Vijaya" FontSize="15" FontWeight="Bold" FontStyle="Normal" />
<Button Content="Zones" Height="23" HorizontalAlignment="Left" Margin="130,58,0,0" Name="btnNoOfZones" VerticalAlignment="Top" Width="41" Click="btnNoOfZones_Click" />
</Grid>
</Grid>
Please any one can suggest me.
Regards,
Viswa.
Just add if condition before apply matrix transform in MouseMove Event in code behind code. The code is as follows:
void Pan_MouseMove(object sender, MouseEventArgs e)
{
if (!((Path)sender).IsMouseCaptured) return;
Point p = e.MouseDevice.GetPosition(clipBorder);
if (p.X > 0 && p.Y > 0 && p.X < clipBorder.ActualWidth && p.Y < clipBorder.ActualHeight)
{
Matrix m = CanvasPanel.RenderTransform.Value;
m.OffsetX = origin.X + (p.X - start.X);
m.OffsetY = origin.Y + (p.Y - start.Y);
CanvasPanel.RenderTransform = new MatrixTransform(m);
}
}
Regards,
Viswa
The x border for the image can be found with the following formula:
let width = image.width;
borderX = Math.ceil(((width * this.currentScale) - width) / (2 * this.currentScale) );
My goal is to create a usercontrol which will redraw when I change its size in designer. For simplicity I created usercontrol Cross. (I am rather a beginner in WPF).
Cross.xaml:
<UserControl x:Class="WpfApplication2.Cross"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Name="Grid1">
</Grid>
</UserControl>
Cross.xaml.cs (without using statements):
namespace WpfApplication2
{
/// <summary>
/// Interaction logic for Cross.xaml
/// </summary>
///
public partial class Cross : UserControl
{
public Cross()
{
InitializeComponent();
Line l = new Line();
l.X1 = 0; l.Y1 = 0; l.X2 = 300; l.Y2 = 300;
l.Stroke = new SolidColorBrush(Colors.Black);
Grid1.Children.Add(l);
l = new Line();
l.X1 = 0; l.Y1 = 300; l.X2 = 300; l.Y2 = 0;
l.Stroke = new SolidColorBrush(Colors.Black);
Grid1.Children.Add(l);
}
}
}
So when I change the size of a Cross in designer from 300 to 600 I want there 2 lines - [0,0,600,600], [0,600,600,0] rather than [0,0,300,300], [0,300,300,0].
Try using The ViewBox Control , Change your xaml to
<UserControl x:Class="WpfApplication2.Cross"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Viewbox>
<Grid Name="Grid1"/>
</Viewbox>
</Grid>
</UserControl>