Draw text on a shape in a wpf - c#

Some of you maybe find this question dull but I am still not deeply accustomed to wpf drawing. I want to add formatted text on a Rectangle which moves around on a canvas and I have got a hint to override the UIElement.OnRender method. However I do not know if I should override the canvas class or the Shape class. In any correct case, to what refers the drawingContext parameter of the method as described in the example: http://msdn.microsoft.com/en-us/library/bb613560.aspx#FormattedText_Object ?
Is the text ultimately assigned to the shape or is it a visual temporary effect that cannot move along with the shape on the canvas?
Is there any further effective means of drawing text on a shape?

You can draw Text on top of a Rectangle by placing both controls in a parent container that allows controls to overlap, such as a Grid or a Canvas
<Grid>
<Rectangle Fill="Red" Stroke="Black"
HorizontalAlignement="Stretch" VerticalAlignment="Stretch" />
<Label Content="Test"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
You can then apply whatever formatting you want to the Label, the Rectangle, and you can move the group around by setting the positioning of the Grid

Rachel's answer is correct, although you can extend it a bit, have some UserControl defined as:
And in the codebehind define 1. Label:String DependencyProperty, Shape:UIElement DependencyProperty.
Handle the Shape's change event and call:
private void UpdateShape()
{
grdShapeContainer.Children.Clear();
if(this.Shape != null)
{
grdShapeContainer.Children.Add(this.Shape);
}
}
This way you will be able to make things dynamic.
Regards,
Artak

You might also want to look into ZIndex property which can be set on objects like Grid (<Rectangle Background="Black" Grid.ZIndex = 99 /> for instance would put it overtop other items) which useful for making things like "loading" screens.

Related

Overlay on Top of DataGrid Content

I have a DataGrid which users can drag and drop files into for them to be imported into the program. I wanted to add some user feedback for when this is happening, so I have put an overlay over the DataGrid when the user drags and drops. The current look of the overlay is this:
I don't like the way the overlay goes over the top of the DataGrid header. If possible, I'd like to confine the overlay to the content only. Does anyone know of some way I could do this? I know I could hard code the height of the header or perhaps create a custom control but the more lightweight/unobtrusive the solution the better in my opinion. Here's a diagram of what I want in case it wasn't clear:
More information: In my current implementation I simply have both the DataGrid and the overlay inside a Grid, and turn the opacity of the overlay on and off as needed. The skinny rectangle under my DataGrid is a loading bar. I'd prefer the overlay not to go over that either, although it doesn't in the current implementation so I don't think that's an issue.
Edit: Here's how I ended up solving it, it's pretty quick and dirty but it works.
private void UserControl_Loaded(object sender, RoutedEventArgs e) {
var header = WPFHelper.FindVisualChild<DataGridColumnHeadersPresenter>(FilesDataGrid);
// Include outside border in margin
var border = FilesDataGrid.BorderThickness;
Thickness margin = new Thickness(border.Left, border.Top, border.Right, border.Bottom);
margin.Top += header.ActualHeight;
OverlayGrid.Margin = margin;
}
There is nothing more "lightweight/unobtrusive" than setting the top-margin of the overlay element to the actual height of the header. So if you don't want to overcomplicate things, you could just set the Margin to a hardcoded value of 23.96:
<Grid>
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Header="..." Binding="{Binding}" />
</DataGrid.Columns>
</DataGrid>
<Border Background="Silver" Opacity="0.5" Margin="0 23.96 0 0" />
</Grid>
The more flexible solution would be to write a behaviour that finds the DataGridColumnHeadersPresenter in the visual tree and set the top-margin of the overlay element to its ActualHeight.

How do I reference a rectangle created programmatically, with XAML?

I am working with WPF for the first time. I am creating a rectangle object & adding it as a child of a canvas.
How do I reference it in XAML?
I want to be able to rotate it over time but don't know how to access it from the MainWindow.xaml code...
I haven't been able to find an answer to this anywhere (maybe you can't do it this way?)
Edit:
I tried setting the Name property of the rectangle to Test (in C# code) and then doing
<Rectangle x:Name="Test">
<Rectangle.LayoutTransform>
<RotateTransform Angle="-45"/>
</Rectangle.LayoutTransform>
</Rectangle>
(This didn't work)
If you create a control in C#, you cannot access it in XAML. I think you must create the necessary animation in C# too.
Applying your rotation in C# could look like this:
var rect = new Rectangle();
rect.LayoutTransform = new RotateTransform() { Angle = -45 };
parentPanel.Children.Add(rect);
The better way would be to generate the Rectangle in XAML and apply there the animation. But this depends on your exact situation. e.g. you can create a single Rectangle in XAML and use this one or you can bind an ItemsControl and create a Rectangle in the ItemTemplate for each entry in the binded list.

How to custom-paint a GridSplitter

I'm migrating form WinForms to WPF, and I need to custom-draw a gridsplitter, as follows. This is my WinForms implementation:
In WinForms it's easy to implement. I inherited from the Splitter class and just override the OnPaint() method.
Now, I'm trying to figure out how to proceed. I don't know how to use a control template in XAML because I need to re-paint the shapes as the user moves the scroll. Seems that I need to write code behind, but I don't know how to proceed.
How might I proceed? A simple example, such as drawing a line from (0,0) to (gridsplitter.right, gridsplitter.bottom) would help.
Finally, I created a Canvas-derived class to perform the rendering:
public class DiffSplitterCanvas : Canvas
{
public DiffSplitterCanvas()
{
this.SnapsToDevicePixels = true;
}
protected override void OnRender(DrawingContext dc)
{
base.OnRender(dc);
// draw your stuff here
}
}
And referenced it as a control template from the XAML code:
<GridSplitter Grid.Column="1" Width="50" HorizontalAlignment="Stretch">
<GridSplitter.Template>
<ControlTemplate TargetType="{x:Type GridSplitter}">
<custom:DiffSplitterCanvas/>
</ControlTemplate>
</GridSplitter.Template>
</GridSplitter>
You could try painting to a WriteableBitmap and using that as the background for the splitter. That might involve overwriting the splitter's template to get things exactly right. I'm not sure how performant that will be with scrolling though.
WriteableBitmap provides only lowlevel access to pixels, if you want higher level functions like drawing lines and circles you may want to look in to a library like WriteableBitmapEx that extends the class with GDI like drawing commands.
Code to set a GridSplitter's background:
<GridSplitter x:Name="gridSplitterTreeNodes" Width="5" BorderThickness="1,0"
Cursor="SizeWE" RenderTransformOrigin="-1.2,0.507" ShowsPreview="True"
Style="{DynamicResource GridSplitterStyle1}">
<GridSplitter.Background>
<ImageBrush ImageSource="Images\gripDots.png" TileMode="FlipXY"
Stretch="UniformToFill"/>
</GridSplitter.Background>
</GridSplitter>
You would want to set the ImageBrush to your WritableBitmap.
Drawing a simpleLine using WriteableBitmapEx:
writeableBmp.DrawLine(1, 2, 30, 40, Colors.Green);

Setting position of Image control relative to screen

I am currently learning C# in my spare time but have become stuck. I am trying to move an Image control to a random position (Horizontal) on the screen, this is done based on the screen size and the size of the image control itself. Is it possible to set a Image.X and Image.Y position within C# and WPF?
You'll probably want to use a Canvas panel for this, as it allows you to position children at X,Y coordinates.
<Canvas>
<Image x:Name="myImage" Canvas.Top="100" Canvas.Left="200" />
</Canvas>
The Canvas.X and Canvas.Y are attached properties. You can set them from code-behind like this:
myImage.SetValue(Canvas.Left, 200);
myImage.SetValue(Canvas.Top, 400);

Changing Display color of PNG with transparency in XAML

I have some PNGs with transparency that I use for buttons in my WPF/C# application.
Right now I have two versions of each PNG, one for normal view and one for hover, each a different color. However, I would really like to just have one single PNG and maybe make everything that's not transparent white (each image is all one color, no detail other than shape.
Would it be possible to then alter the color of each using a SolidColorBrush or similar and create the Normal/Hover versions as a static resource in my XAML?
Something like this:
<Image Key="BtnMenu" Source="Images/Menu.png" Fill="ButtonNormalBrush" />
<Image Key="BtnMenuHover" Source="Images/Menu.png" Fill="ButtonHoverBrush" />
Yeah, I totally made up the "Fill" thing...
But the basic idea is that I have a ResourceDictionary that contains the color scheme that is used throughout the entire application, which makes it so that I can change any of the about 6 colors I use in the application in one place and it updates on every control that references that color... but the one place I cannot do it is those PNGs for the buttons. (Ideally in the future I'll make that ResourceDictionary something that can be loaded in at runtime to make the application have alternate "skins"..but right now the PNGs keep me from doing that).
Edit: BTW, if the solution requires a Converter or something written in code, that's totally fine.
Hmm... If you created a Grid, and put the Image inside that Grid, you could set the Background of the Grid to your fill color.
Edit: Here is some code:
<Button>
<Grid Background="SkyBlue">
<Image Source="img.png" Stretch="None" />
</Grid>
</Button>
There is a solution: http://msdn.microsoft.com/ru-ru/library/ms752364.aspx
You can simply create ImageSource with new Format-object from another ImageSource. Format object specifies color mask for an Image.
You could try to apply a ShaderEffect as the Effect on the hover image or create a markup extension which transforms your image. Another possibility would be to encapsulate such logic in a subclass of Image.

Categories

Resources