Quick question about the Rectangle constructor in System.Windows.Shapes. I'm trying to create a Rectangle object using the following code.
Rectangle rect1 = new Rectangle(5,5,5,5);
However, I get an error saying that the Rectangle constructor doesn't take 4 arguments. After some extensive research, the documentation gives a couple explicit constructors, such as these two.
Rectangle(int32,int32, int32, int32);
and
Rectangle(Point, Size);
I have tried using both, and it accepts neither, giving the error that the Rectangle class doesn't accept either 2 or 4 arguments. However, when I don't pass it any arguments, it works fine. The issue is that there is no way to access the location of the Rectangle, so I can only change the width and height after creating the object, not the location.
Disclaimer:
This is indeed part of a homework assignment, but a very, very small piece of a larger whole, and as I have spent a lot of time on this one simple problem(so I assume), therefore, I have no qualms about asking here.
After some back and forth in comments, this is what you actually want: A UI element in a Canvas, depicting a rectangular shape.
var rect = new System.Windows.Shapes.Rectangle();
// Capital C Canvas: Static methods of System.Windows.Canvas, setting what are
// called "attached properties" in WPF. This is very weird if you're new to WPF, sorry.
Canvas.SetLeft(rect, 5);
Canvas.SetTop(rect, 5);
rect.Height = 5;
rect.Width = 5;
// canvas, lowercase c, is your instance of System.Windows.Canvas
canvas.Children.Add(rect);
With WPF, I prefer to work in XAML rather than C# for creating UI elements:
<Canvas Width="300" Height="300">
<Ellipse
Stroke="DeepSkyBlue"
Width="30"
Height="30"
Canvas.Left="40"
Canvas.Top="40"
/>
<Rectangle
Stroke="Black"
StrokeThickness="1"
Canvas.Left="20"
Canvas.Top="20"
Width="100"
Height="100"
/>
</Canvas>
Other possible answers, none applicable in this case
If you're in winforms, use System.Drawing.Rectangle instead. That's the one you were reading the documentation for (kudos for actually reading documentation -- few do).
You may possibly have to add to your project a reference to System.Drawing.dll (in References in the project tree in VS).
In WPF, you can use that class, or System.Windows.Rect. That one uses double precision floating point values instead of integers. Pick whichever is appropriate to the task at hand. UI stuff in WPF is all floating point, so Rect may be best.
The one in Shapes is something else.
If System.Windows.Shapes is in your using lines at the top, delete that if you can.
But if you need to keep that, this always works in cases of ambiguity:
var rect = new System.Drawing.Rectangle(5,5,5,5);
var r2 = new System.Windows.Rect(5,5,5,5);
In .Net there are two Rectangle classes:
System.Drawing.Rectangle(Int32,Int32,Int32,Int32);
System.Drawing.Rectangle(Point, Size);
and
System.Windows.Shapes.Rectangle();
Change the namespace as below. Add a reference to System.Drawing.dll if required.
//using System.Windows.Shapes;
using System.Drawing;
Related
I am trying to get some animations working where I smoothly change the material of various shapes so that they are transparent/different colors.
The issue is:
If I look into the shape from above I can see the inner corners of it (say if it's a cube I can see the inner surface of it), but anything outside/beyond the perimeter of the shape is occluded.
So far I am doing the following, which works great besides that problem:
Color c = new Color()
{
A = 16,
R = Colors.Transparent.R,
G = Colors.Transparent.G,
B = Colors.Transparent.B
};
(model as GeometryModel3D).Material = new DiffuseMaterial(new SolidColorBrush(c));
(model as GeometryModel3D).BackMaterial = new DiffuseMaterial(new SolidColorBrush(c));
If I drop the alpha of the color all the way to 0, the shape becomes opaque, seemingly because the shape is invisible but it's still occluding whatever is behind it.
The information I've found so far suggested that using emissive or specular materials would work because it didn't get written to the Z-buffer, but either diffuse materials don't work the same or I implemented that wrong.
Edit:
After coming across this question: StackOverflow, and seeing the comment under the first answer, I'm assuming being able to make objects truly transparent must be more involved than I first thought. That person seems to have had the same trouble as me.
Sounds like your surfaces might be oriented the wrong way. If so, you can fix it by reversing the order of the vertices for each element of the cube.
The standard rasterization pipeline typically draws "one-sided" primitives -- i.e., it will only draw triangles it thinks are facing the camera. That way, for instance, it doesn't even have to try to draw the back-facing sides of your cube.
One more solution that helped me is using Helix toolkit and this example helped a lot
http://helix-toolkit.github.io/demos/wpf/transparency
I imported the models from the stl files and added them as list inside of the
HelixToolkit:SortingVisual3D as Model3DGroup (from Microsoft)
an example of XAML:
<HelixToolkit:SortingVisual3D IsSorting="True" x:Name="sortingVisual1" Method="BoundingBoxCorners" SortingFrequency="2">
<ModelVisual3D Content="{Binding Model3DGroup1, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
<ModelVisual3D Content="{Binding Model3DGroup2, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
<ModelVisual3D Content="{Binding Model3DGroup3, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
<ModelVisual3D Content="{Binding Model3DGroup4, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
</HelixToolkit:SortingVisual3D>
Every group is one separate .stl file
My problem was that when uploaded stl files, the outer one wouldn't let the light through for the inner models no matter the opacity
this is the function for the bound model in VM:
private readonly HelixToolkit.Wpf.ModelImporter _importer = new HelixToolkit.Wpf.ModelImporter();
var model = _importer.Load(stlPath);
var m0 = (MeshGeometry3D)((GeometryModel3D)model.Children[0]).Geometry;
var insideMaterial = MaterialHelper.CreateMaterial(outsideColor, 0.6);
return new GeometryModel3D { Geometry = m0, Material = insideMaterial };
I seem to be unable to figure out how to Draw graphics in a Windows phone app in C#.
I want to Draw e.g. a line. In old school Windows forms i add an event handler to the Windows paint event. And then use a GDI+ Graphics object. But there is no paint event in any controls?
So how do i draw a line on a canvas in a Windows phone app?
I think I need to clarify.
I want to create dynamic graphics and I want to use C#.
I want an update frequency arround 30 fps and I only need a few graphics elements approximately 100.
if you need a line, use the Line class:
<Page xmlns="whatever">
<Grid>
<Line X1="0" Y1="0" X2="10" Y2="10" Stroke="Blue" StrokeThickness="2"/>
</Grid>
</Page>
Other than that, refer to MSDN.
Forget whatever procedural paradigms you might have learned in archaic technologies. Modern technologies are declarative.
You start by adding Canvas to the form and then .Add() graphical objects to the canvas children - it makes the object scaled for you by the engine, which is kind of neat. Usually looks like this:
line = new **Line**();
line.Stroke = Brushes.Yellow;
line.X1 = 0;
line.Y1 = 0;
line.X2 = 100;
line.Y2 = 100;
line.StrokeThickness = 2;
yourCanvas.Children.**Add(line)**;
Just drop the **s from the code - they are for attention grabbing.
Actually, as I drew dynamic hypercubes, I have never used the XAML version, but if you need a static structure or even substructure XAML is the way to go. As I understand, Children.Add() dynamically creates node in the parsed XAML tree, that .NET keeps in memory. If you can not take slight performance hit for dynamicly positioned graphics that WPF imposes, you will have to stick with DirectX or OpenGL for better performance.
If you want low level access to draw 2D or 3D like when using DirectX you can take a look to SharpDX
There are some samples for Windows Phone in Github like:
MiniCube: Display a rotating cube in a DrawingSurfaceBackgroundGrid
I have a Canvas with 2 "dots" drawn on it. See this (simplified) code:
<Canvas>
<Ellipse />
<Ellipse />
<Canvas.RenderTransform>
<RotateTransform x:Name="rotateEllipse" />
</Canvas.RenderTransform>
</Canvas>
As you can see, I want to rotate the canvas using the given RotateTransform.
Next, I want to put a TextBlock near to each Ellipse (a label). However, I don't want to include this TextBlock into the Canvas because it will then rotate also. I want the text to remain horizontal.
Any idea how to solve this in an elegant way?
Something like this, should work for you
<TextBlock RenderTransform="{Binding RelativeSource={RelativeSource AncestorType=Canvas},
Path=RenderTransform.Inverse}"/>
Assign to text box transformation matrix an inverse of the transformation matrix of the Canvas.
Good question! And I'm going to guess, so please take this answer with a pinch of salt.
I believe you are trying to place text annotations next to ellipses on a rotated canvas, but these annotations need to remain horizontal. Two things you could try:
Firstly, given the XY point that you know of each ellipse from Canvas.GetTop/GetLeft, you could find its new rotated XY location by applying the RotateTransform to the ellipse location, using the formula U = M*V, where U is the output point, V is the input point (XY location of ellipse) and M is the Rotation Matrix.
Secondly, you could place a second canvas over the first (assuming they are both in a grid, the second canvas is at higher Z-index and is the same size as the underlying canvas). Call it an annotation layer. Your annotations (text labels) can appear at the new transformed locations and unrotated using this approach.
You'd have to do this in code of course, not Xaml, although you might find a binding friendly approach by creating a value converter on the TextBlock that bound to the source RotateTransform/Ellipse and did this operation for you.
Another approach would be to take the .Inverse of the RotateTransform and apply that to the textblocks, however you may still need to translate to get to the new location. Either way I think it demands some experimentation.
Best regards,
How do you get the REAL position of objects in silverlight?
I have a header image centered on the screen. When I make the browser window smaller, obviously, the header's left side goes off the screen. Finding out the actual position is good to know if you want to position objects on top of the image.
I capture the Content_Resized and I run a little test:
if (App.Current.Host.Content.ActualWidth > header.Width)
{
TEST = Canvas.GetLeft(header);
}
else
{
TEST = Canvas.GetLeft(header);
}
TEST always returns zero.
EDIT: header sits on a grid instead of a canvas. "Well, there is your problem..." So a better question might be this. How would I get the margins of an image sitting on a grid?
I probably should just answer the question but how to find the position of an element relative to another is probably something that has been answered before (by myself and others) here and elsewhere on the tinternet.
However if your goal is to place an item over an image then place the image in a Grid and then add the item as child of the Grid. That way you assign the relative position over the image as the margin of the item and let Silverlight's layout system do the rest.
As a general rule if you feel that you need to write code to move stuff about when the size of things change then unless you are writing a custom panel or something you're probably not using Silverlight layout system properly.
Edit:
Try this experiment:-
<Grid x:Name="LayoutRoot">
<Grid x:Name="headerContainer" Margin="50, 60, 0, 0" HorizontalAlignment="Left" VerticalAlignment="Top">
<Image Source="YourLargeImage" />
<Image Source="YourSmallerImage" HorizontalAlignment="Center" VerticalAlignment="Top" />
</Grid>
</Grid>
Now try changing the inner grid's Margin to move its position around the screen. Note the smaller image always remains at the top center of the large image.
I got it working.
First of all, these images are on a grid, not a canvas. But switching the grid to a canvas caused lots of other problems one of which is that I could not have the header image centered like before.
The solution was to change the margin of the smaller image sitting on top of the larger header image when the content resized like this:
blankbarimage.Margin = new Thickness((App.Current.Host.Content.ActualWidth - header.Width) / 2, 0, 0, 0);
and, by the way, you create a content resized method like this:
App.Current.Host.Content.Resized += new EventHandler(Content_Resized);
So, to answer my own question, the way you get the REAL position of object in silverlight is (if they are on a grid) by looking at their margin settings.
I am trying to write a small interactive game-like application, where I need to have a Draw method that's gonna draw on screen, but can't figure out how to structure the method for WPF.
If this was Winforms, I could use:
public void Draw (Graphics g)
{
}
But for a WPF Window, what should I have on it in the xaml (currently only have a Grid), and what should this Draw method receive as an argument?
First I want to do it like this to get it working, then I can think about how to make it more WPF, etc. But now I am more interested in getting this to work.
Typically, you "draw" in WPF in a completely different manner.
In Windows Forms/GDI, the graphics API is an immediate mode graphics API. Each time the window is refreshed/invalidated, you explicitly draw the contents using Graphics.
In WPF, however, things work differently. You rarely ever directly draw - instead, it's a retained mode graphics API. You tell WPF where you want the objects, and it takes care of the drawing for you.
The best way to think of it is, in Windows Forms, you'd say "Draw a line from X1 to Y1. Then draw a line from X2 to Y2. Then ...". And you repeat this every time you need to "redraw" since the screen is invalidated.
In WPF, instead, you say "I want a line from X1 to Y1. I want a line from X2 to Y2." WPF then decides when and how to draw it for you.
This is done by placing the shapes on a Canvas, and then letting WPF do all of the hard work.
When there are just too many objects to be drawn very quickly (huge Visual Tree) another option would be to use a WriteableBitmap. Just use the Pixels property to set the pixels and/or use the Render method to draw UIElements.
I preffer to use OnRender method like in this example:
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
drawingContext.DrawRectangle(null, new Pen(Brushes.Black, 2), new Rect(0, 0, ActualWidth, Height));
}
To Implement a Draw loop type behavior in WPF you can use the CompositionTarget.Rendering event. This is raised once per frame when the WPF drawing system is painting frames.
As others have pointed out this is not very WPF friendly but it will work and can be used to get more immediate drawing behavior out of a WPF app.
In most cases you would use a single root canvas and update say the Canvas position of an element on the CompositionTarget.Rendering event.
For example to make a ellipse fly all over the screen do this:
In your XAML (For a Window that is 640 by 480 in size):
<Canvas x:Name="theCanvas">
<Ellipse x:Name="theEllipse" Height="10" Width="10" Fill="Black" />
</Canvas>
In your Code behind for the Window that the above XAML is in (Make sure to add a reference to System.Windows.Media in order to see the CompsitionTarget object :
public static Random rand = new Random();
public View()
{
InitializeComponent();
CompositionTarget.Rendering += CompositionTarget_Rendering;
}
void CompositionTarget_Rendering(object sender, System.EventArgs e)
{
double newLeft = rand.Next(0, 640);
double newTop = rand.Next(0, 480);
theEllipse.SetValue(Canvas.LeftProperty,newLeft);
theEllipse.SetValue(Canvas.TopProperty, newTop);
}
Yow should add a Canvas (or change the Grid for a Canvas) and then draw over it. Here is Microsoft tut on drawing over a canvas
Also, I don't know how related is this other question to yours, but you might want to check it out.