Wpf Draw Bitmap on Canvas
In the previous exercise, Solved tasks for C# .NET WPF lessons 6-10, we've practiced our knowledge from previous lessons.
In the previous lesson, Solved tasks for C# .NET WPF lessons 6-10, we finished our birthday reminder. We tried the basic form controls on it, as well as bindings and error handling. We're already able to create quite sophisticated applications. In today's C# .NET WPF tutorial, we're going to draw.
Drawing on Canvas
We'll create an application to manage the sales of cinema tickets. As we know, there are many seats in the cinema hall, and the application should show the cinema worker which seats are already occupied. You might be thinking of adding a Button
control for each seat. However, if the cinema had 15 rows with 30 seats each, we'd have 450 Button
controls. You probably expect there should be a better way than start typing Button1
, Button2
... And how would they be handled then? If we need to draw something more complex than just one or two pictures, we can use Canvas
. The point is we place a single Canvas
on the form and draw all we need on it.
We'll simplify the cinema application, it doesn't need to be complex. It'll be able to display only a single hall, which will be empty at the start. The user clicks on the seats to make them occupied, and then presses the "Save" button, which saves all the information about the occupancy of the hall to a simple txt file in the chosen location. We'll do the saving to learn how to work with dialogs.
Form Design
Create a new WPF Application, set the window title to Cinema hall administration
. Set the WindowStartupLocation
property to CenterScreen
. This will ensure that the window will always appear in the center of the screen when the application is launched.
For the form design, we'll use the Grid
control we already know very well from the previous lessons. The layout of the application isn't very complicated, so we can split the grid into two rows. The first row will contain the Canvas
and the second one will contain a Button
with the Save
text. Add a Click
event to the button and generate a Code Behind method that is called when the user clicks the button. Your form should look like this:
And here is its corresponding XAML code:
<Window x:Class= "Cinema.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:Cinema" mc:Ignorable= "d" Title= "Cinema hall administration" WindowStartupLocation= "CenterScreen" Height= "450" Width= "600" > <Grid> <Grid.RowDefinitions> <RowDefinition Height= "350" ></RowDefinition> <RowDefinition Height= "*" ></RowDefinition> </Grid.RowDefinitions> <Canvas Name= "MyCanvas" Margin= "20 50 0 0" ></Canvas> <Button Name= "Save" Click= "Save_Click" Content= "Save" Grid.Row= "1" Height= "20" Width= "100" ></Button> </Grid> </Window>
Logical Layer
You are probably not surprised that we're going to add a Cinema
class to our application. It'll have single private field, a two-dimensional array of seats. If you haven't worked with a 2D array yet, you can think of it as a table. A one-dimensional (classic) array is actually just a single row. We then work with the 2D array exactly the same as with a one-dimensional array, except that we have to specify two coordinates (X and Y). In many languages, 2D arrays are created as array of arrays, but C# can define 2D arrays directly as follows:
class Cinema { private bool[,] seats = new bool[30, 15]; }
The seats are of the bool
type, because we only need to know whether they are vacant or occupied. 30
is the width of the array, 15
is its height.
We'll also add two private constants to the class, the first one defining the size of the rendered seat in pixels, and the other one defining the space between the seats also in pixels. Get used to constants. When you decide to change the seat size, then you'll just need to overwrite a single constant, without having to mess with the entire rendering code.
private const int size = 16; private const int space = 2;
We can now move on to methods.
Insert Rectangles
We've already mentioned that we're going to draw on the canvas. Individual rectangles representing the seats will be represented as objects that we'll place on the canvas using a DrawRectangles()
method. The canvas is of the Canvas
type, and we'll request it as a parameter in the method. You'll need to add using System.Windows.Shapes
to make the Rectangle
class available. When we'll place individual rectangles on the Canvas
, we'll always set their width and height to the size
constant, and then set the appropriate color using the Fill
property and the static Brushes
class. It contains pre-made instances set to certain colors, just pick any.
Using two nested loops, we'll go through all the seats in the array and draw either a green or a red square on the canvas. We'll use the outer loop to go through the rows, and the inner loop to go through each column in the current row. The color (more precisely the brush) is determined by whether the seat at the given coordinates is true
or false
. The method's code will be as follows:
public void DrawRectangles(Canvas MyCanvas) { for (int j = 0; j < seats.GetLength(1); j++) { for (int i = 0; i < seats.GetLength(0); i++) { Rectangle rectangle = new Rectangle { Height = size, Width = size, }; rectangle.Fill = seats[i, j] ? Brushes.Red : Brushes.Green; MyCanvas.Children.Add(rectangle); Canvas.SetLeft(rectangle, i * (size + space)); Canvas.SetTop(rectangle, j * (size + space)); } } }
Notice that we don't use the values of 30
and 15
in the loops, but we use the GetLength()
method with parameters 0
and 1
instead. This method is used to obtain the size of a two-dimensional array. 0
is the width, and 1
is the height (of course, it depends on us which dimension we treat as the height or the width).
Of course, we don't hard-code the array size because in the future we may want to increase / decrease it without having to search the entire code for the values 30
and 15
. It's always better to avoid these problems and work with the array length instead.
It's worth mentioning the rendering of the rectangles themselves. We can see that we render them by adding each Rectangle
instance as a child to our Canvas
. Then, in order to display the rectangles exactly where we want, it's necessary to set up their positions. We use the static Canvas
class, which contains the SetLeft()
and SetTop()
methods, which represent the coordinates of the upper-left corner of the rectangle. Since every seat is 16
pixels wide + 2
pixels of empty space, we need to multiply its coordinates by that value. If the i
had the value of 2
(when drawing the third column), we'd draw the rectangle at the X coordinate of 36
, rather than the 2
The same applies to the Y coordinate.
Wiring the Form and the Logic Layer
The base of the logic is complete, now let's wire it to the form. We'll go to the Code Behind of the form and create a private Cinema
instance there:
private Cinema cinema = new Cinema();
Now it's really simple. On the cinema instance, we'll call the DrawRectangles()
method and pass our Canvas
to it, which we defined in the form, as a parameter. To render the seats when we launch the application, we'll put this code in the form constructor in the Code Behind.
public MainWindow() { InitializeComponent(); cinema.DrawRectangles(MyCanvas); }
We really don't have to be ashamed of the result:
In the next lesson, Handling Rectangle Clicks in C# .NET WPF, we'll show how to change the seat state by clicking on it, and implement saving to a file. As always, you can download the project below, in case something went south for you.
Did you have a problem with anything? Download the sample application below and compare it with your project, you will find the error easily.
chamblissclate1979.blogspot.com
Source: https://www.ictdemy.com/csharp/wpf/drawing-on-canvas-in-csharp-net-wpf/
0 Response to "Wpf Draw Bitmap on Canvas"
Postar um comentário