How can I get the elements of a canvas?
I have this:
<Canvas x:Name="can" HorizontalAlignment="Left" Height="502" Margin="436,0,0,0" VerticalAlignment="Top" Width="336" OpacityMask="#FFC52D2D">
<Canvas.Background>
<SolidColorBrush Color="{DynamicResource {x:Static SystemColors.ActiveCaptionColorKey}}"/>
</Canvas.Background>
<Button x:Name="btn_twoThreads" Content="Two Threads" Height="32" Canvas.Left="195" Canvas.Top="460" Width="131" Click="btn_twoThreads_Click"/>
<Button x:Name="btn_oneThread" Content="One Thread" Height="32" Canvas.Left="10" Canvas.Top="460" Width="131" Click="btn_oneThread_Click"/>
<Rectangle Fill="#FFF4F4F5" Height="55" Canvas.Left="10" Stroke="Black" Canvas.Top="388" Width="316"/>
</Canvas>
As you can see there are some objects on this canvas in the XAML Code. I need to get the the Rectangle object's details:
Rectangle r;
r = can.Children[2] as Rectangle; //I know this probably doesn't retrieve the rectangle object, but hopefully you can see what I am trying to achieve.
if (r != null)
{
MessageBox.Show("It's a rectangle");
}
I know I could probably just access the Rectangle object by just giving it a variable name in the XAML, but the canvas object is being drawn to in various classes, and I don't want to pass the rectangle to every class if it is already contained within the canvas.
You could try this:
// to show that you'll get an enumerable of rectangles.
IEnumerable<Rectangle> rectangles = can.Children.OfType<Rectangle>();
foreach(var rect in rectangles)
{
// do something with the rectangle
}
Trace.WriteLine("Found " + rectangles.Count() + " rectangles");
The OfType<>() is very useful because it checks the type and only yields an item if it is the right type. (it's casted already)
Related
So I am creating a "Map Viewer" for a program I am working on. Basically I want to display a map and have it resize the image to fit in the grid. For this I am using Viewbox to hold the image and resize it. I was attempting to use this code to reveal the map but it does not center the circle on the mouse and it does not retain the revealed portions of the map (it ONLY reveals where the mouse is and not where it has been).
Here is the XAML:
<Viewbox x:Name="MapHolder" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="1" Grid.RowSpan="7" Margin="25,5,25,15">
<Image x:Name="SelectedMap" Source="/wizard_dungeon.jpg" Stretch="Uniform" MouseMove="SelectedMap_MouseMove" >
<Image.OpacityMask>
<VisualBrush Stretch="None" >
<VisualBrush.Visual>
<Ellipse Width="400" Height="400" StrokeThickness="1" Fill="Black"/>
</VisualBrush.Visual>
<VisualBrush.RelativeTransform>
<TransformGroup>
<TranslateTransform x:Name="OpacityFilterTransform" X="1" Y="1"/>
</TransformGroup>
</VisualBrush.RelativeTransform>
</VisualBrush>
</Image.OpacityMask>
</Image>
</Viewbox>
And the code-behind:
private void SelectedMap_MouseMove(object sender, MouseEventArgs e)
{
var position = e.GetPosition(this);
var height = MapHolder.ActualHeight;
var width = MapHolder.ActualWidth;
// with the position values, interpolate a TranslateTransform for the opacity mask
var transX = position.X / width;
var transY = position.Y / height;
OpacityFilterTransform.X = transX - 0.5;
OpacityFilterTransform.Y = transY - 0.5;
}
I want there to basically be a Image under a Black screen and I can erase the black screen to reveal the image in the areas I have erased.
I am trying to make a drawing program in WPF but I ran into some problems.
I can succesfully draw lines (yeeey) but I also want the ability to fill out space (my method is stacking alot of recntagles with the same starting point).
but when I switch my radiobutton from "line" to "fill" it doesnt draw anything.
-- drawing (boolean) is used to create the starting point of filling
Code
private void cnvs_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed && linemode.IsChecked == true)
{
Line line = new Line();
drawing = true;
line.Stroke = currentbrush;
line.X1 = currentPoint.X - 9;
line.Y1 = currentPoint.Y - 9;
line.X2 = e.GetPosition(this).X - 9;
line.Y2 = e.GetPosition(this).Y - 9;
currentPoint = e.GetPosition(this);
cnvs.Children.Add(line);
} else if (cnvs.IsFocused == true)
{
if (!drawing) rectbeggining = e.GetPosition(this);
drawing = true;
Rectangle rect = new Rectangle();
rect.Stroke = currentbrush;
rect.StrokeThickness = 1;
rect.Height = (Math.Abs(e.GetPosition(this).Y) - Math.Abs(rectbeggining.Y));
rect.Width = (rectbeggining.X - e.GetPosition(this).X);
Canvas.SetLeft(rect, e.GetPosition(this).X);
Canvas.SetTop(rect, Math.Abs(e.GetPosition(this).Y));
cnvs.Children.Add(rect);
}
if(e.LeftButton == MouseButtonState.Released) drawing = false;
}
Xaml
<Grid>
<Border Name="CanvasBorder" BorderBrush="Black" BorderThickness="2" Margin="8,8,207,9"/>
<Canvas HorizontalAlignment="Left" Height="972" Margin="10,10,0,0" VerticalAlignment="Top" Width="1493" MouseDown="Canvas_MouseDown" MouseMove="cnvs_MouseMove" Name="cnvs">
<Canvas.Background>
<SolidColorBrush Color="White" Opacity="0"/>
</Canvas.Background>
</Canvas>
<ComboBox Name="selectcolor" Margin="1510,10,10,945" SelectedItem="Black" SelectionChanged="selectcolor_SelectionChanged" SelectedIndex="7">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="{Binding Name}" Width="16" Height="16" Margin="0,2,5,2" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button Content="Reset" HorizontalAlignment="Left" Margin="1510,939,0,0" VerticalAlignment="Top" Width="192" Click="Button_Click" Height="44"/>
<RadioButton GroupName="selectedMode" Name="linemode" Content="Line" HorizontalAlignment="Left" Margin="1510,232,0,0" VerticalAlignment="Top" IsChecked="True"/>
<RadioButton GroupName="selectedMode" Name="fillmode" Content="Fill" HorizontalAlignment="Left" Margin="1510,247,0,0" VerticalAlignment="Top"/>
<Label Content="Mode:" HorizontalAlignment="Left" Margin="1510,206,0,0" VerticalAlignment="Top"/>
</Grid>
I'm working on the map editor for generalstaff at the moment. You pick between line or area types of terrain, draw and when you finish a stroke it's processed.
Unless I've misunderstood your purpose that sounds pretty much like you're doing.
I essentially have an inkcanvas on top of a canvas.
It's rather more complicated than that. I bind viewmodels to an itemscontrol which has a canvas as it's itemspresenter and template data into the pieces of terrain.
I can bore at length on this stuff.
I use inkcanvas because it gives you smoother results than drawing directly on a canvas. I started off using a canvas like that but you get jiggly bits..
The strokeschanged event is used to tell when a stroke on the inkcanvas has finished.
Each stroke has a styluspointcollection StylusPoints and you can iterate through that to get the points.
Once you have the points, you can build a polygon.
I do that by templating and I bind the Points property of a Polygon to a Pointcollection from a viewmodel.
A polygon has a Fill property which you can set or bind to a solidcolorbrush.
And in that way you can draw any shape you like, then fill it with one colour.
I am building an application like a noteBook in Landscape.
I have two canvas next to each other and I'm changing the Background inside them.
Every time I write on the two canvas and move to another 2 backgrounds, I need to save what I wrote on the two canvas and reload it once I move to these backgrounds once again, and clear them. And do the same for all the backgrounds.
<Grid x:Name="RenderedGrid" Width="1140" Height="770">
<ScrollViewer x:Name="DScrollViewer" MaxZoomFactor="2.0" MinZoomFactor="1.0" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" ZoomMode="Disabled">
<StackPanel Orientation="Horizontal">
<Canvas x:Name="inkCanvas0" HorizontalAlignment="Left" Width="570">
<Canvas.Background>
<ImageBrush x:Name="DImage0" ImageSource="{Binding}"/>
</Canvas.Background>
</Canvas>
<Canvas x:Name="inkCanvas1" HorizontalAlignment="Right" Width="570">
<Canvas.Background>
<ImageBrush x:Name="DImage1" ImageSource="{Binding}"/>
</Canvas.Background>
</Canvas>
</StackPanel>
</ScrollViewer>
</Grid>
I need to bind the Canvas in a way to this class instead of inkCanvas0 & inkCanvas1:
public class MyCanvas
{
public Canvas inkCanvas { get; set; }
}
List<MyCanvas> CanvasList = new List<MyCanvas>();
This is how I am creating Empty Canvas and storing them in CanvasList:
for (int i = 0; i < 24; i++)
{
Canvas canvas = new Canvas();
canvas.Name = "inkCanvas" + i;
MyCanvas mc = new MyCanvas();
mc.inkCanvas = canvas;
CanvasList.Add(mc);
}
I need to Bind these Canvas to the its corresponding page (inkCanvas0 to page0)
but I'm getting an exception in Xaml when I try to bind the Name of the Canvas.
<Canvas x:Name="{Binding}" HorizontalAlignment="Left" Width="570">
Exception: Catastrophic failure The name already exists in the tree.
How can I solve this? Is my logic of creating and loading the Canvas correct?
I have a wrap panel with images in it. I am using a pointing device and can get X and Y coordinates on screen. I would like to use the X and Y coordinates to select a particular item in the WrapPanel or List.
<WrapPanel HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Row="1" Name="ImageWrap">
<ContentControl Style="{StaticResource imageContainerStyle}">
<Image Stretch="Uniform" Source="/Images/Texture01.jpg" />
</ContentControl>
<ContentControl Style="{StaticResource imageContainerStyle}">
<Image Stretch="Uniform" Source="/Images/Texture02.jpg" />
</ContentControl>
<ContentControl Style="{StaticResource imageContainerStyle}">
<Image Stretch="Uniform" Source="/Images/Texture03.jpg" />
</ContentControl>
</WrapPanel>
C# code which I am trying to use. But isn't working
Point mousePosition = new Point(xPosition, yPosition);
Point localPoint = this.ImageWrap.PointToScreen(mousePosition);
Please provide me with suggestions.
You may use the panel's InputHitTest method. It will return the element at the given position (in coordinates relative to the panel), or null, as long as you don't set the panel's Background property.
Point screenPosition = new Point(xPosition, yPosition);
Point panelPosition = ImageWrap.PointFromScreen(screenPosition); // not PointToScreen
IInputElement element = ImageWrap.InputHitTest(panelPosition);
if (element is Image)
{
...
}
I have two images, as explained in the following XAML code:
<Window x:Class="TestApplicationGestureKinect.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="768" Width="1024" ScrollViewer.VerticalScrollBarVisibility="Disabled" MinWidth="1024" MaxWidth="1024" MinHeight="768" MaxHeight="768">
<Grid Background="Black">
<Image x:Name="img1" HorizontalAlignment="Left" Margin="47,82,0,0" VerticalAlignment="Top" Source="photos/01.jpg" Height="200" RenderTransformOrigin="0.5,0.5" >
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="9.577"/>
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
<Image x:Name="cursorRight" HorizontalAlignment="Left" Margin="757,133,0,0" Width="48" Height="48" VerticalAlignment="Top" Source="cursors/right_open.png" />
</Grid>
</Window>
And the following image shows how this appear:
I need a way to test, from C# code, if the image called cursorRight is onto the area covered by the image called img1, after the transformation.
How could I do? I thought about some consideration on the bounding boxes of the two images, but while for the cursorRight image, could be acceptable to consider the bounding box, this doesn't seem to be a good choice for the other image......
EDIT: The following images show four examples of how I want to do:
cursor on the image:
cursor not on the image:
SOLUTION: The following code is what I used in order to solve the above problem. I considered the bounding box of the cursor rather than the exact shape of it.
private bool isOn(Image img1, Image img2)
{
if (img1 == null || img1.Visibility != System.Windows.Visibility.Visible)
{
return false;
}
double img1_topLeft_X = img1.Margin.Left;
double img1_topLeft_Y = img1.Margin.Top;
double img1_bottomRight_X = img1_topLeft_X + img1.Width;
double img1_bottomRight_Y = img1_topLeft_Y + img1.Height;
Point img1_topLeft = new Point(img1_topLeft_X, img1_topLeft_Y);
Point img1_bottomRight = new Point(img1_bottomRight_X, img1_bottomRight_Y);
HitTestResult result_topLeft = VisualTreeHelper.HitTest(img2.Parent as Grid, img1_topLeft);
HitTestResult result_bottomRight = VisualTreeHelper.HitTest(img2.Parent as Grid, img1_bottomRight);
if (result_topLeft != null && result_bottomRight != null)
{
if (result_topLeft.VisualHit.GetType() == typeof(Image) && result_bottomRight.VisualHit.GetType() == typeof(Image) &&
(result_topLeft.VisualHit as Image).Name.Equals(img2.Name) && (result_bottomRight.VisualHit as Image).Name.Equals(img2.Name))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
However, in this way the cursor is ONTO the image only if the bounding box of it is TOTALLY onto the image. It's not exactly what I needed, but since it works pretty well, I decided to use this method.
An option not quite would be to use the VisualTreeHelper.HitTest(...) methods to check if points overlapped each other. You can read more about it works here.
Use bounding rectangle for your cursor and a "bounding polygon" that defines the area of your larger image and then use polygon intersection algorithm (one explanation here) to solve your problem.