How To Draw Text In Wpf
WPF excels at creating nifty looking applications.
One of the ways you lot tin make your application look peachy is to add some shapes like circles, triangles and rectangles. Withal, the shapes in WPF practice not permit you to add text (or any content) within the shape, as shapes are not containers.
In a WPF application I am building correct now, I take a need to create different shapes and center text inside those shapes. The shapes I need are rectangles, circles, ellipses and triangles. The problem is WPF shapes are non containers and then you cannot add whatever text inside of them, merely WPF is flexible enough that in that location are oftentimes several ways to work around this. In this article, I will show y'all a few dissimilar methods of centering text in each of these shapes.
Drawing an Ellipse/Circle Using a Border
If you wish to put text into an ellipse or a circumvolve, you can simulate this using a Border control and play with the Width, Padding and CornerRadius backdrop of the Border control. I used the lawmaking snippet below to draw text within an ellipse as shown in Figure 1.
<Border CornerRadius="fifty" Width="60" Margin="10" Padding="four" Background="Aquamarine" BorderBrush="Black" BorderThickness="i"> <TextBlock HorizontalAlignment="Eye" Text="Exam" /> </Edge> You tin set the width and height of the Border command to create a circle also. The XAML in the next snippet creates a circumvolve with text in the heart, equally shown in Figure two.
<Border CornerRadius="l" Width="lx" Height="threescore" Margin="10" Padding="0,20,0,0" Background="Aquamarine" BorderBrush="Black" BorderThickness="1"> <TextBlock HorizontalAlignment="Center" Text="Test" /> </Border> Depict a Triangle Using a Visual Castor
To create a triangle shape in WPF y'all use a Polygon command. If you remember your high schoolhouse math, a Polygon is a serial of continued lines that have the aforementioned get-go and end point. The XAML beneath creates a triangle; notwithstanding, in that location is no text in information technology because a Polygon is not a container.
<Polygon Points="25,0 5,30 45,xxx" Fill="LightBlue" Stroke="Blackness" StrokeThickness="2" /> To add text similar that shown in Effigy three, you need to apply the Polygon control as the background of a TextBlock command. The XAML shown in List 1 is used to create Figure iii.
Two key things make this XAML work. First, you use the VisualBrush object of the Background of the TextBlock object to requite you a place to put the Polygon control. 2nd, depending on the text that you fill into the TextBlock control, and the width and pinnacle of the TextBlock control, you volition demand to play with the Padding holding to align the text to the correct location. Take the to a higher place XAML and put it in a new window so conform the height, width and text values. Y'all will meet that you need to conform the Padding property to make the text fall into the right location within the Polygon.
List 2 shows another example of a Visual Brush, this time using an Ellipse control. Figure 4 shows the results of the XAML in Listing 2.
Notice the Padding attribute is different than when using the Polygon control. Yous will need to make minor adjustments based on the shape that y'all are using and the elevation and width of the control, and the text you are putting into the TextBlock.
Position a Shape on a Sail
Using a Visual Brush inside a TextBlock control works, merely information technology is not very re-usable code. The ultimate goal of this article is to show you lot how to move all of this lawmaking into one user control that you can utilise over and over once more. Before yous tin learn that technique, you get-go need to learn to use a Canvas, a Shape, a TextBlock and MultiBinding converters.
You lot use a WPF Canvass control to position child controls at a specified betoken on the Canvass. I created Effigy 5 past placing a shape (you can use any control) at a certain indicate by setting the attached backdrop "Canvas.Pinnacle" and "Sheet.Left". In Effigy v you lot tin come across that the circle is positioned 20 points below the pinnacle of the Canvas and 40 points to the right of the Canvass' leftmost border. I used the XAML below to create Figure v.
<Sheet Name="cnvMain" Width="80" Superlative="80"> <Ellipse Canvas.Peak="twenty" Sail.Left="forty" Width="40" Meridian="40" Fill="Greyness" /> </Canvas> Place a Shape within a Canvas
Virtually of the time, you want a shape to take upward the same amount of width and height as the Sail. So, you tin can only set the Width and Top backdrop of both the Canvas control and the Shape control to be exactly the aforementioned. Since the Shape control is the kid inside the Sail, it will fill up up the whole Canvas. Notation that you exercise non demand to specify the Canvas.Superlative and Canvass.Left as the default for these is zippo (0) for any child control placed in a Canvas equally shown in the following XAML.
<Canvass Proper name="cnvMain" Width="80" Height="80"> <Ellipse Width="80" Height="80" Make full="Greyness" /> </Canvas> Bind Ellipse Width and Superlative to Canvas
The problem with the above XAML is that if you lot wish to alter the width and the acme of the Sail and you want the shape to exist the exact same meridian, you demand to alter four numbers. Instead of hard-coding the numbers on the Shape control, you lot tin take advantage of the element-to-element binding features of WPF. Below is an example of binding the Width and Top of the ellipsis to the Width and Pinnacle of the Sheet. The XAML below will produce the circle shown in Figure 6.
<Canvas Name="cnvMain" Width="lxxx" Top="fourscore"> <Ellipse Width="{Binding ElementName=cnvMain, Path=ActualWidth}" Acme="{Binding ElementName=cnvMain, Path=ActualHeight}" Fill="Gray" /> </Sail> Using a MultiBinding Converter
Now that you lot have a Shape inside a Canvas you lot can identify a TextBlock in the center of the Canvas to display text in the middle of that Shape. To center a TextBlock in the eye of a Sail you need to take the width of the Canvas and subtract the width of the TextBlock, then divide this by 2 to get the value for the Left belongings. You utilise the same calculation for height to become the Top property of where to position the TextBlock in relation to the peak of the Canvas.
Information technology would be actually convenient if you could use an expression in a WPF binding since you lot could then perform this calculation, merely you tin't. So, instead, you lot need to laissez passer the width of the Canvas and the width of the TextBlock to some code you write, and also the height of the Canvas and TextBlock. This is where a MultiBinding converter comes in very handy.
The result of the MultiBinding converters, shown in Listing 3, is to set the "Sheet.Left" and "Canvas.Height" backdrop of the TextBlock control. If you are familiar with a normal WPFbinding markup extension, you empathize how a converter class is used to convert a single input value and produce a single output value that you assign to a holding. A MultiBinding converter allows you to pass more than one value to a converter form. Notice the "Converter={…}" attribute uses a StaticResource called Midvalue. This static resource is divers in the Window.Resource section of this window as follows:
<Window.Resources> <src:MidpointValueConverter x:Key="MidValue" /> </Window.Resources> The MidPointValueConverter class implements the IMultiValueConverter interface. This interface defines the Convert and ConvertBack methods just similar a normal value converter method. It is your job to write the code to take the multiple inputs that are passed to the "values" parameter to the Convert method and render a single value that tin be used to ready the Left holding. Listing 4 shows the MidPointValueConverter class.
In the MidPointValueConverter class you grab the two values passed in, which are the total width/elevation of the Sheet, and and so the total width/height of the TextBlock control. Y'all can then subtract those 2 values and divide by two to get the location of either the Left or the Top holding.
Notice that y'all can also pass in an "extra" value in the "parameter" parameter. You can employ this extra value if you want to move the TextBlock control downward or to the right depending on the shape you employ. For instance, if y'all are using a triangle with the point of the triangle at the summit, yous might want to move the text a little lower into the widest function of the triangle instead of right in the middle of the triangle. Or, if you have a triangle where the signal is to the right, then you lot might want to motility the text a piddling over to the left. You set this "actress" parameter as the ConverterParameter attribute on the MultiBindingXAML chemical element equally shown in Listing 5.
Effigy 7 shows the results of the rectangle with text in it, and the result of using a polygon with the ConverterParameter set.
Creating a User Control for Hosting Shapes
So, up to this indicate y'all accept at present learned how to create shapes and center text inside those shapes using a couple of different methods. Now it is time to wrap up all this functionality into a squeamish, re-usable user control. In Figure 8 you see a couple of shapes that were created using a user control chosen "ucShape". The first 1 draws a circle with the name "Paul" in it while the 2d 1 is a triangle.
Listing six shows the XAML used to create the circle in Effigy 8. Notice each of the properties you can set on the user control. You can fix the text to display on the shape using the TextToDisplay property. Y'all employ the Shape belongings to specify which type of shape yous wish to display. You tin use six unlike shapes with this user control; Rectangle, Square, Triangle, InvertedTriangle, Ellipse and Circumvolve. Other backdrop that you can ready include the color of the shape, the text, and the height and width of the shape.
Listing 7 shows the XAML lawmaking that draws the triangle shown in Figure 8. I've sent the ShapeToCreate holding in this sample to "Triangle". Notice the boosted properties HeightOffset and WidthOffset. Usually the text is centered directly in the middle of the shape but with a triangle you will desire to move the text to the fattest role of the triangle. These ii additional properties adjust the text up, downward, left or correct.
Build a Shape User Control
To create your own shape user control y'all add a user control named ucShape to your project and add each of the backdrop shown in List 7. You will need to fix up an enumeration for each shape as seen in the lawmaking below.
public enum ShapeEnums { Rectangle, Square, Triangle, InvertedTriangle, Ellipse, Circle } You create the appropriate property go and set up statements within the user control for each of the properties in Listing 7. I am not going to list the lawmaking for those here equally I presume you lot know how to create normal properties. Yous can become the consummate source code (in C# or VB) for this user command by downloading the sample code at world wide web.pdsa.com/downloads.
The User Control XAML
Listing eight is the complete XAML for your ucShape user control. A Sail command is the container control for the entire user control. Yous'll use the Canvas command to middle the text at a specific point on the command. Find that you do not utilize a shape control in the user command. The lawmaking will create the shape at run fourth dimension by examining the ShapeToCreate property and adding the appropriate shape onto the Canvass at the appropriate location.
Observe the binding extensions on the Sheet control to the ActualWidth and ActualHeight properties of the user control. When yous set the Width and Meridian properties on the user control these values will be used to set the Canvas to the same height.
The TextBlock control is contained within the Sail control, merely no other backdrop are assail this control. The properties such every bit where to place the TextBlock control on the Sheet, the Foreground color, the text, etc., will be set up dynamically at run fourth dimension based on the properties you lot attack the user control.
Loading the User Control
When an case of the ucShape user control is loaded, the code creates the shape based on the ShapeToCreate property. The appropriate backdrop on the TextBlock control such every bit the Text, the Top and Left volition also exist set at this time. The Pinnacle and Left properties of the TextBlock will be ready through the MultiBinding converter created in lawmaking this time equally opposed to in the XAML.
Listing 9 shows the code for the Loaded event on the ucShape user control. This event procedure calls a method named CreateShape which is where the logic for creating each of the shapes is located. If a valid shape is returned from the CreateShape method, then that shape is inserted equally the starting time control on the Sheet control.
The Loaded effect procedure sets the Foreground property on the TextBlock command from the TextColor property set when the user control was declared. Finally, the MultiBinding converter for the Left and Acme properties on the TextBlock command are created by calling the SetWidthMultiBinding and SetHeightMultiBinding. You volition see this lawmaking a little later on in this article.
The CreateShape Method
The CreateShape method (Listing 10) is fairly directly-forward WPF code. It contains a switch argument that checks the ShapeToCreate property. Based on that holding, the appropriate shape is created and advisable Width and Summit backdrop on the shape are leap to the Width and Height backdrop on the Canvas control.
Create a MultiBinding in Lawmaking
In Listing 5 you saw how to use a MultiBinding converter to pass in 2 parameters from XAML and get a single value returned. Since you have moved all of the code into the user control, y'all volition now create these MultiBinding converters in code too. Listing 11 shows the code for calculating the Left and Top properties for the TextBlock. Yes, you could have still created the MultiBinding converters in XAML, but I thought it would exist skillful to evidence you how to perform the aforementioned thing using WPF code.
Summary
In this commodity, you learned how create text centered on a shape using a few different methods. It but goes to show that there are always several methods to accomplish the same matter in WPF. For a quick and dingy arroyo, using a VisualBrush within a TextBlock works quite well. Using a user control is the all-time approach when you want to re-use the shape and text over and over over again. You tin can identify the user control and all the associated code into a DLL to reuse in many applications.
Listing 1: Place Text in a Triangle using a Visual Brush
<TextBlock Text="Test" Width="50" Height="50" Padding="13,28,0,0"> <TextBlock.Background> <VisualBrush> <VisualBrush.Visual> <Polygon Points="25,0 5,30 45,30" Make full="LightBlue" Stroke="Blackness" StrokeThickness="2" /> </VisualBrush.Visual> </VisualBrush> </TextBlock.Groundwork> </TextBlock> Listing ii: Place Text in an Ellipse using a Visual Castor
<TextBlock Text="Test" Height="40" Width="40" Padding="eight,ten,0,0"> <TextBlock.Groundwork> <VisualBrush> <VisualBrush.Visual> <Ellipse Pinnacle="20" Width="twenty" Fill="LightBlue" /> </VisualBrush.Visual> </VisualBrush> </TextBlock.Groundwork> </TextBlock> List three: Utilize MultiBinding converters to perform calculations and assign the result to backdrop
<Canvas Name="cnvMain" Width="xl" Peak="40"> <Rectangle Name="rectSize" Make full="Blue" Width="{Binding ElementName=cnvMain, Path=ActualWidth}" Tiptop="{Binding ElementName=cnvMain, Path=ActualHeight}" Stroke="Blackness" StrokeThickness="2" /> <TextBlock Name="tbSize" Foreground="White" Text="Test"> <Canvas.Left> <MultiBinding Converter="{StaticResource MidValue}"> <Binding ElementName="cnvMain" Path="ActualWidth" /> <Binding ElementName="tbSize" Path="ActualWidth" /> </MultiBinding> </Canvass.Left> <Sail.Top> <MultiBinding Converter="{StaticResource MidValue}"> <Binding ElementName="cnvMain" Path="ActualHeight" /> <Binding ElementName="tbSize" Path="ActualHeight" /> </MultiBinding> </Canvas.Top> </TextBlock> </Canvas> List four: The MidPointValueConverter class takes multiple inputs to produce a unmarried output
C# using System; using System.Globalization; using Organisation.Windows.Information; public grade MidpointValueConverter : IMultiValueConverter { #region Convert/ConvertBack Methods public object Convert(object[] values, Blazon targetType, object parameter, CultureInfo civilisation) { double kickoff = 0; double totalMeasure = 0; double controlMeasure = 0; // Make sure enough "values" were passed if (values == aught || values.Length < two) { throw new ArgumentException("The MidpointValueConverter class requires 2 double values to exist passed to it. First pass the total measure of the outside control, then the total measure out of the control to be placed within the outside control.", "values"); } // Go the full width/peak totalMeasure = (double)values[0]; // Go the width/elevation of the control controlMeasure = (double)values[1]; // cheque for any outset to the width/height if (parameter != null) start = Organization.Convert.ToDouble(parameter); return (object)(((totalMeasure - controlMeasure) / 2) + commencement); } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo civilization) { throw new NotImplementedException(); }

0 Response to "How To Draw Text In Wpf"
Post a Comment