I am a bit new to WPF. I wanted to make my image scrollable when I scale up the image. This is my XAML code.
<UserControl xmlns: skia="clr-namespace:SkiaSharp.Views.WPF:assembly=SkiaSharp.Views.WPF">
<Grid>
<skia:SKElement Name="Canvas" PaintSurface="SKElement_PaintSurface">
</Grid>
</UserControl>
private void SKElement_PaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
\\Code goes here...
}
Inside the SKElement_PaintSurface method, I created a way to draw the bitmap image on the canvas. But when I scale up the image I can't scroll the image. Does anyone know to create a scrollbar for this?
Put the Canvas in a ScrollViewer element and set its Height and/or Width when you scale it:
<UserControl xmlns: skia="clr-namespace:SkiaSharp.Views.WPF:assembly=SkiaSharp.Views.WPF">
<Grid>
<ScrollViewer>
<skia:SKElement Name="DrawCanvas" PaintSurface="SKElement_PaintSurface">
</ScrollViewer>
</Grid>
</UserControl>
private void SKElement_PaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
\\Code goes here...
DrawCanvas.Height = 100;
}
Related
Is there a way in WPF to access the ScaleTransform Parameter of a Canvas Panel (which is created in the xaml File) in the Code Behind File?
Use Case Example:
I want to position a list of items inside a scaled Canvas like so:
<ItemsControl MouseMove="Control_MouseMove">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas>
<Canvas.RenderTransform>
<TransformGroup>
<ScaleTransform>
<ScaleTransform.ScaleX />
</ScaleTransform>
</TransformGroup>
</Canvas.RenderTransform>
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
I also want to display the current position of my items inside the Canvas at Mouse over with a Pop-up. I am currently trying it this way:
public void Control_MouseMove(object sender, MouseEventArgs e) {
if (!this.Popup.IsOpen)
this.Popup.IsOpen = true;
var mousePosition = e.GetPosition(this.SwLane);
this.Popup.HorizontalOffset = mousePosition.X + 10;
this.Popup.VerticalOffset = mousePosition.Y - 20;
this.PopupContent.Text = System.Convert.ToString(mousePosition.X);
}
What I get is the canvas X coordinate inside the Popup (which makes sense to me). However, I would like to display the scale transformed "coordinates" of the canvas.
Is there a way to access the ScaleTransform Parameter in Code Behind so that I can visualise my transformed item position? Or should I do it in a different way? Thanks.
You could set an OnInitialized Handler where you build your transform in code-behind, save its constituent ScaleTransform as a private property and then assign it there as well after your window has initialized
Something crudely like this:
<Window x:Class="WpfApp4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="White"
MouseLeftButtonDown="MainWindow_OnMouseLeftButtonDown"
Initialized="MainWindow_OnInitialized"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ItemsControl x:Name="MyItems" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<Rectangle Width="100" Height="200" Stroke="Red" StrokeThickness="5"/>
</Grid>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private TransformGroup MyTransform { get; set; }
private ScaleTransform SceneScale { get; set; }
private void MainWindow_OnInitialized(object? sender, EventArgs e)
{
MyTransform = new TransformGroup();
SceneScale = new ScaleTransform(1.0, 1.0, 0, 0);
MyTransform.Children.Add(SceneScale);
MyItems.RenderTransform = MyTransform;
}
}
Now you could add a MouseLeftButtonDown Handler to scale things, for example:
private void MainWindow_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
SceneScale.ScaleX *= 1.1;
SceneScale.ScaleY *= 1.1;
}
For the coordinate thing, expose the current coordinates as properties. Update them when the mouse moves. Bind the UI to them
This might work better if you packaged it all in a control
I have a grid containing an Image (with 2 rows top and bot that I will use later) and another grid containing 4 radio button.
When user click on image, a cross is displayed on the point where he clicked.
There is a part of code :
<Grid Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Image Grid.Row="0"
x:Name="ImageViewer"
Source="{Binding Picture}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
MouseDown="Image_MouseDown"
MouseMove="ImageViewer_MouseMove"
MouseUp="Image_MouseUp"/>
<local:Cross Grid.Row="0"
CenterPoint="{Binding Point1}"
Foreground="Red"/>
<!-- Grid.Row="1" - Grid with RadioButtons -->
</Grid>
With events :
protected bool StartMove = false;
private void Image_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
StartMove = true;
Point p = e.GetPosition(ImageViewer);
DrawPoint(p);
}
}
private void Image_MouseUp(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
StartMove = false;
}
}
private void ImageViewer_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed && StartMove)
{
Point p = e.GetPosition(ImageViewer);
DrawPoint(p);
}
}
When image is perfectly sized (no border), the cross is correctly drawn. Clicking on my cat eye made this :
But if I resize my window, the cross is moving. I guess that the coordinates are computed considering the white spaces but I don't know how to prevent this.
There it is with the same point :
The cross is drawn by local:Cross element. This element layout is matching to Image and you expect it to draw cross relative to Image.
And it does.
The problem is what Image (disregards it's stretching its size) also stretching its source image. You can try to set Image.Stretch to Fill or solve the problem by using another layout (e.g. Stretch="None", making position and size of Cross and Image equal).
In fact, it is your image that is moving not the cross.
Your problem is that your are catching the position relative to Image UI element, so when you resize your main window you are also resizing your Image element.
Possible solutions:
Fixed size Image element
or, Recalculate the position of your cross when resize
or, Keep your image aligned to top left in your Image
I have a wpf Application where's two grid inside one single grid like this
<window ....>
<grid x:name="main_grid">
<grid x:name="panel1">
//...some stuff//
</grid>
<grid x:name="panel2">
//...some stuff//
</grid>
</grid>
</window>
the main_grid is positioned to fit the whole window
I want to position Panel1 and Panel2 margin left and top to 0 from code behind.
what I tried is like this,
private void window_Loaded(object sender, RoutedEventArgs e)
{
int left = Convert.ToInt16(main_grid.Margin.Left);
int top = Convert.ToInt16(main_grid.Margin.Top);
panel1.margin = new Thickness(left, top, 0, 0);
panel2.margin = new Thickness(left, top, 0, 0);
}
However, it's not working. figures...
Anybody have any solutions? please...
Why not in XAML like this:
<Grid x:name="main_grid"
Margin="10,20,30,40">
<Grid x:name="panel1"
Margin="10,20,30,40">
</Grid>
<Grid x:name="panel2"
Margin="10,20,30,40">
</Grid>
</Grid>
I have the following XAML:
<Window x:Class="thumb_test.MainWindow" Title="MainWindow" ... >
<Grid>
<Canvas>
<Thumb Canvas.Top="25" Canvas.Left="25" Width="50" Height="50"
Name="_thumb1" DragStarted="ThumbStart" DragDelta="ThumbMoved" >
</Thumb>
</Canvas>
</Grid>
</Window>
And the following is the corresponding code-behind:
void ThumbStart(object sender, DragStartedEventArgs e)
{
_originalLeft = Canvas.GetLeft(_thumb1);
_originalTop = Canvas.GetTop(_thumb1);
}
void ThumbMoved(object sender, DragDeltaEventArgs e)
{
double left = _originalLeft + e.HorizontalChange;
double top = _originalTop + e.VerticalChange;
Canvas.SetLeft(_thumb1, left);
Canvas.SetTop(_thumb1, top);
_originalLeft = left;
_originalTop = top;
}
The above displays a rectangle, which can be dragged around on the canvas.
My question: How can I associate this Thumb with a TextBlock, such that the Thumb overlays the TextBlock (with the Thumb being transparent) and I can drag the TextBlock around? (PS: Believe me, what I have tried so far is not worth showing here.)
My ultimate goal is to be able to drag TextBlocks around, so I am open to other approaches. I would like to operate on a Canvas, though.
I am using VS2010 on Win 7, with .NET 4.0.
have you read Dragging Elements in a Canvas ?
or this easy way(that i never saw until now -google) How to make any UI element drag-able using Behaviors in WPF
I'm trying to drag and drop an image from one spot on the canvas to another (should be relatively simple), but can't figure it out. The image which I want to move has the following XAML:
<Image Height="28" HorizontalAlignment="Left" Margin="842,332,0,0" Name="cityImage" Stretch="Fill" VerticalAlignment="Top" Width="42" Source="/Settlers;component/Images/city.png" MouseLeftButtonDown="cityImage_MouseLeftButtonDown" MouseMove="cityImage_MouseMove" MouseLeftButtonUp="cityImage_MouseLeftButtonUp"/>
The code is as follows:
bool isDragging = false; Point initMousePos; private void cityImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
isDragging = true;
initMousePos = e.GetPosition(theGrid); } private void cityImage_MouseMove(object sender, MouseEventArgs e) {
if (isDragging)
{
Image image = sender as Image;
Canvas.SetTop(image, initMousePos.X);
Canvas.SetLeft(image, initMousePos.Y);
image.Visibility = System.Windows.Visibility.Visible;
} }
private void cityImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
isDragging = false; }
What I do to accomplish what you want is to use
System.Windows.Controls.Primitives.Thumb
as the Root of a UserControl and set the ControlTemplate to display an image (within a border but it should work without as well), something like:
<Thumb Name="myRoot" DragDelta="MyRootDragDelta">
<Thumb.Template>
<ControlTemplate>
<Image ... >
... see below ...
</Image>
</ControlTemplate>
</Thumb.Template>
</Thumb>
Also, I bind the Source of the Image to a property of the class:
<Image.Source>
<Binding Path="ImageSource" RelativeSource=
{RelativeSource FindAncestor,
AncestorType=my:MyImageControl, AncestorLevel=1}" />
</Image.Source>
The UserControl has a named TranslateTransform (let's say translateTransform) whose properties X and Y are to be set in the DragDelta event handler:
private void MyRootDragDelta(object sender, DragDeltaEventArgs e)
{
translateTransform.X += e.HorizontalChange;
translateTransform.Y += e.VerticalChange;
}
Don't forget to add:
public ImageSource ImageSource { get; set; }
Hope this helps. If anything's unclear feel free to ask further.
You want to set the Left and Top properties of the Canvas to something other than the initial position. In the MouseMove handler you have to get the position relative to the parent. Also; make sure the parent element is a canvas and not a grid. You have a pretty big left and top margin on the image, aswell as a control with the variable name "theGrid".