Binding to ActualHeight does not work - wpf

I tried to create a custom control, having a semitransparent rounded background:
<Canvas>
<TextBlock x:Name="StopText" Text="Some test text"/>
<Rectangle Fill="SkyBlue"
Width="{Binding Source=StopText, Path=ActualHeight}"
Height="20"
RadiusX="5" RadiusY="5" Opacity="0.2"/>
</Canvas>
The problem is that I can't, probably, bind to the ActualHeight/ActualWidth properties, cause they are not dependency ones.
What to do to mantain the rectangle and textbox of same size?

The correct binding is to use ElementName, not Source, when binding to another element:
<Canvas>
<TextBlock x:Name="StopText" Text="Some test text"/>
<Rectangle Fill="SkyBlue"
Width="{Binding ElementName=StopText, Path=ActualHeight}"
Height="20"
RadiusX="5" RadiusY="5" Opacity="0.2"/>
</Canvas>
Also, you do realize that you are binding the width of the Rectangle to the Height of the TextBlock, right?
If this is really the way you want to set up your control, you will want to bind the Rectangle's Width to the TextBlock's ActualWidth, and Height to ActualHeight.
UPDATE
Per the comments below, here is an implementation using a Grid with no binding:
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock x:Name="StopText" Text="Some test text"/>
<Rectangle Fill="SkyBlue"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
RadiusX="5" RadiusY="5" Opacity="0.2"/>
</Grid>
Grid and Canvas use different layout systems, and since you aren't using the functionality the Canvas provides, Grid is the better choice.
The big difference in the child elements is that the Rectangle now just uses Horizontal and VerticalAlignment to Stretch across the entire Grid, instead of worrying about the sizes of anything.

Related

My canvas stretches vertically and horizontally, but the image inside does not

I'm creating a popup menu a ToggleButton and a Popup control. All of which are contained within a canvas. The following image is of the bottom right corner of my application. I set my Canvas so that's in the Index 1 column, stretches 2 columns, and is in the second to bottom row.
The gray image is just a place holder. From the XAML below, you can see that I've set everything to stretch. The Canvas stretches, but nothing else does. Commenting out the StackPanel and/or the Label does nothing. So I'm convinced neither are the cause. The ToggleButton isn't stretching to the size of the Canvas.
I did a screenshot so I could highlight those relevant portions, better. But if I need to paste the code, I can.
EDIT
Updated XAML:
<Border BorderBrush="Green" BorderThickness="1" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid Name="ToggleButtonCanvas" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<ToggleButton x:Name="btnPluginMenu" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<ToggleButton.Template>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border x:Name="bdr" BorderThickness="0">
<Border.Background>
<ImageBrush ImageSource="< omitted >" Stretch="Fill" TileMode="None" />
</Border.Background>
<ContentPresenter VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="8,6,8,6" ContentSource="Content" />
</Border>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<Label Canvas.Left="10" Canvas.Top="10" Content="Menu" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
</StackPanel>
<Popup Placement="Relative" HorizontalOffset="-120" VerticalOffset="-130" PlacementTarget="{Binding ElementName=btnPluginMenu}" IsOpen="{Binding ElementName=btnPluginMenu, Path=IsChecked}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" PopupAnimation="Scroll">
<Grid Background="Gray">
<Grid.BitmapEffect>
<DropShadowBitmapEffect />
</Grid.BitmapEffect>
</Grid>
</Popup>
</Grid>
</Border>
Canvas does not stretch its child elements. Use a Grid instead.
From the Remarks in the Canvas documentation in MSDN:
Canvas is the only panel element that has no inherent layout
characteristics. A Canvas has default Height and Width properties of
zero, unless it is the child of an element that automatically sizes
its child elements. Child elements of a Canvas are never resized, they
are just positioned at their designated coordinates. This provides
flexibility for situations in which inherent sizing constraints or
alignment are not needed or wanted. For cases in which you want child
content to be automatically resized and aligned, it is usually best to
use a Grid element.
You can simply replace Canvas by Grid in your XAML. There is no need to define rows or columns.

Stretch items to fill canvas

I have a Dockpanel with items inside a Canvas. The Dockpanel and any other items (Grid etc) that I place inside the Canvas, only take up their minimum required space. How do I stretch these items to fill the entire Canvas?
<Canvas x:Name="InfoCanvas" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="72,53,0,0">
<DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0,0,0,0" x:Name="ReferenceInfo" Canvas.Left="0" Canvas.Top="0">
<TextBox x:Name="ReferenceAuthor" GotFocus="FieldEnter" LostFocus="FieldLeave" FontSize="16" FontFamily="Segoe UI Light" Text="Author" Foreground="Gray" Background="Transparent" DockPanel.Dock="Top" VerticalAlignment="Top" HorizontalAlignment="Stretch" BorderThickness="0" Margin="0,2,0,2"/>
<TextBox x:Name="ReferenceTitle" GotFocus="FieldEnter" LostFocus="FieldLeave" FontSize="16" FontFamily="Segoe UI Light" Text="Title" Foreground="Gray" Background="Transparent" DockPanel.Dock="Top" VerticalAlignment="Top" HorizontalAlignment="Stretch" BorderThickness="0" Margin="0,2,0,2"/>
<TextBox x:Name="ReferenceDate" GotFocus="FieldEnter" LostFocus="FieldLeave" FontSize="16" FontFamily="Segoe UI Light" Text="Date" Foreground="Gray" Background="Transparent" DockPanel.Dock="Top" VerticalAlignment="Top" HorizontalAlignment="Stretch" BorderThickness="0" Margin="0,2,0,2"/>
</DockPanel>
</Canvas>
Thank you!
The Canvas panel doesn't really support that.
It's very basic - it just allows you to position children absolutely by using Top, Bottom, Left and Right, and it always gives them just the space they need.
So usually you would use a Grid with just 1 column and 1 row instead.
You can however bind the width and height of the DockPanel to the width and height of the Canvas. That way the DockPanel will always fill the Canvas.
<DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Margin="0,0,0,0" x:Name="ReferenceInfo" Canvas.Left="0" Canvas.Top="0"
Width="{Binding ActualWidth, ElementName=InfoCanvas}"
Height="{Binding ActualHeight, ElementName=InfoCanvas}">
What you can do is:
<Grid>
<Canvas x:Name="InfoCanvas">
<!--Elements with canvas layout here-->
</Canvas>
<DockPanel x:Name="ReferenceInfo">
<!--Elements with dockpanel layout here-->
</DockPanel>
</Grid>
By wrapping both panels in a grid like this you can place elements that you cant to position relative to left, top etc in the canvas. Both the canvas and the dockpanel will fill available space. Note that the elements in the dockpanel will be rendered above the elements in the canvas when the dockpanel is defined after in xaml.
I'm assuming the code you posted is pseudo code, if not you should just remove the canvas.

Visual brush weird behavior

I have a textbox and a rectangle. The rectangle updates itself when textbox content changes. I'm painting the rectangle fill with visual brush. The problem is that the visual brush don't match the textbox's actual look. What should I do. Here's my code:
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox Name="txtBox"/>
<Rectangle Height="{Binding ElementName=txtBox, Path=ActualHeight}"
Width="{Binding ElementName=txtBox, Path=ActualWidth}">
<Rectangle.Fill>
<VisualBrush Visual="{Binding ElementName=txtBox}"/>
<Rectangle.Fill>
<Rectangle.LayoutTransform>
<ScaleTransform ScaleY="-0.75"/>
</Rectangle.LayoutTransform>
</Rectangle>
</StackPanel>
Here I wrote "Visual Brush",
then deleted few chars and look what I got:
Made a small change to your Xaml based on the information in your comment. The problem seems to be that the TextBlock doesn't have a Background so I guess that the VisualBrush just finds the visible part of the TextBlock for rendering and then stretches it to the full length of the TextBlock based on the Bindings.
The following Xaml works fine when the TextBlock has Background="Transparent" but reproduces your problem without it
Update: In the chat, the OP found that the Width Binding kept the TextBox from shrinking when deleting characters. So removing the Width binding fixes the centering issue as well.
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox Name="txtBox"/>
<TextBlock Name="textBlock" Text="{Binding ElementName=txtBox, Path=Text}"
Background="Transparent"/>
<Rectangle Height="{Binding ElementName=textBlock, Path=ActualHeight}">
<Rectangle.Fill>
<VisualBrush Visual="{Binding ElementName=textBlock}"/>
</Rectangle.Fill>
<Rectangle.LayoutTransform>
<ScaleTransform ScaleY="5"/>
</Rectangle.LayoutTransform>
</Rectangle>
</StackPanel>

WPF - drawing text onto a GridSplitter

I am declaring this Grid Splitter:
<GridSplitter HorizontalAlignment="Right" VerticalAlignment="Stretch" Grid.Column="1" Grid.RowSpan="1" Grid.Row="1" Width="5" Background="#FFBCBCBC" ResizeBehavior="PreviousAndNext">
</GridSplitter>
It is a vertical grid splitter and I want to draw some text using RotateTransform so the text runs from top to bottom. I am having trouble getting it to work.
This should render the text as rotated.
<TextBlock Text="Testing" HorizontalAlignment="Center" VerticalAlignment="Center" IsHitTestVisible="False">
<TextBlock.LayoutTransform>
<RotateTransform Angle="90" />
</TextBlock.LayoutTransform>
</TextBlock>
You would then need to include it after your GridSplitter in the same column. The IsHitTestVisible is just in case it interferes with the mouse.
EDIT: Just to be clear, this would be a child of the Grid, not the GridSplitter. It would simply render on top of the GridSplitter.

WPF Scaling Issue

I am perplexed with an issue that I am experiencing, using ScaleTransform. I have a Grid with a fixed width and height. The grid contains one child, a Rectangle. The Rectangle's Fill is a VisualBrush whose Visual binds to a canvas outside of the grid, whose dimensions are rather large. On the rectangle, I use a ScaleTransform, with ScaleX and ScaleY both being set to 0.18. Essentially, I am trying to scale the Rectangle's visual down to fit within my grid. What appears to be happening is that the Grid itself is being scaled down, resulting in a much smaller result than what I want. I have included the code below. Just as a point of reference, the height and width that the rectangle binds do are essentially 900 by 600, respectively. Any pointers as to what I might be doing wrong would be greatly appreciated.
<Grid Height="225" Width="200" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Top" x:Name="PART_Content">
<Rectangle Height="{Binding Path=ActualHeight}" Width="{Binding Path=ActualWidth}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Rectangle.Fill>
<VisualBrush Visual="{Binding}"/>
</Rectangle.Fill>
<Rectangle.RenderTransform>
<ScaleTransform ScaleX="0.183" ScaleY="0.183"/>
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
Can you post the XAML for the Canvas element? I tried the following and I am getting the behavior you are going for (the rectangle is scaled and the grid is sized correctly)
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid ShowGridLines="True" Height="225" Width="200" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Top" x:Name="PART_Content">
<Rectangle Height="{Binding Path=ActualHeight}" Width="{Binding Path=ActualWidth}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Rectangle.Fill>
<VisualBrush Visual="{Binding ElementName=theCanvas}"/>
</Rectangle.Fill>
<Rectangle.RenderTransform>
<ScaleTransform ScaleX="0.183" ScaleY="0.183"/>
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
<Canvas x:Name="theCanvas" Grid.Row="1">
<Rectangle Fill="Brown" Height="300" Width="300" />
</Canvas>
</Grid>
What is ActualWidth and ActualHeight? Unless I am mistaken the ActualHeight and ActualWidth properties as they normally mean in WPF are not DP's and you cannot bind to them. As has been pointed out below these are readonly dependency properties. Assuming this is in a CustomControl style Binding should be changed to TemplateBinding first.
I removed the bindings and essentially created a static version of your XAML which looks just fine. Since you have Part_Content defined for the grid, I am curious, is this xaml part of a custom control style? Is the code of the CustomControl manipulating the grid via PART_Content?
<Grid Height="225" Width="200" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Top" x:Name="PART_Content" Background="Red">
<Rectangle Height="225"
Width="200"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Blue">
<Rectangle.RenderTransform>
<ScaleTransform ScaleX="0.183" ScaleY="0.183"/>
</Rectangle.RenderTransform>
</Rectangle>
</Grid>

Resources