Display non rectangular shaped TextBlock - wpf

I want to display text in a triangular area. But I cannot figure out how to change the shape of the TextBlock so that text is displayed in triangular region instead of the regular rectangular region.
Here is the simplified code of my UserControl:
<Grid >
<Image Height="100" Width="100" /> <!-- Some triangular image -->
<TextBlock Height="100" Width="100" Text="This text should fill up the triangualr image area"/>
</Grid>

Well kind of an overkill solution but the contents of the inner grid will be triangular in arrangement if something similar is followed:
<Grid>
<Image Height="200" Width="200" />
<Grid Width="200">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="2" Grid.ColumnSpan="1" Text="Line 1" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" Text="This is Line 2." HorizontalAlignment="Center"/>
<TextBlock Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="5" Text="This is Line 3. Wud be longest." HorizontalAlignment="Center"/>
</Grid>
</Grid>
For your reference, The grid is constructed as follows :
Set the background triangular image & I suppose that suffices.

You need to overwrite the TextBox's Template
I would recommend getting a copy of Blend, extracting the TextBox's Template from there, and modifying it to suit your needs.
If you are unable to get Blend, I'd recommend Show Me The Template, which is a WPF tool that shows the default template for most WPF controls

Just overwrite the template of the textbox, like this
<ControlTemplate TargetType="Textbox">
<Path ... define your triangle here>
</ControlTemplate>
and then set the enter property on the textbox to true. also align cont. hor. and vert. alg. that way it is centered in the middle of the triangle. make sure you make the textbox background transparent so it doesn't overwrite the triangle bounds.
also if you don't want to go outside the bounds, put the content presenter inside a viewbox.
you can also look into the clip property.

Related

WPF: Scale Grid without scaling content

Is it possible to apply a scale transform a Grid's columns and rows without scaling the content?
I would like the content of each cell to simply resize to fit the cell without being scaled (e.g. font size of text remains the same).
For example, in the following piece of XAML I would like the buttons to resize rather than scale:
<Grid Name="grid1" RenderTransformOrigin="0.5, 0.5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="300" />
<ColumnDefinition Width="300" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="80"/>
<RowDefinition Height="80"/>
</Grid.RowDefinitions>
<Grid.RenderTransform>
<ScaleTransform ScaleX="{Binding Value, ElementName=slider1 }" ScaleY="{Binding Value, ElementName=slider1 }"
/>
</Grid.RenderTransform>
<Button Content="Button3" Margin="6" Name="button3" />
<Button Content="Button4" Grid.Column="1" Margin="6" Name="button4" />
<Button Content="Button5" Grid.Column="2" Margin="6" Name="button5" />
<Button Content="Button6" Grid.Column="0" Grid.Row="1" Margin="6" Name="button6" />
</Grid>
With the method you're applying, this isn't possible because the transform will apply to the rendering of all child controls, too.
However, by the look of your code, you want to resize your grid's columns based on the position of a slider. An easier way would be to set all the columns to Width="*" (which will have the effect of each column having equal width), remove your transform, and bind the width of the grid as a whole to the slider instead (you may need to adjust the range of your slider to suit!).
This will have different effect to a RenderTransform, though, because a RenderTransform won't affect any of the surrounding layout, and changing the Width will. Post a comment if that will be a problem and maybe there's another solution...

WPF Frame - Size to content

I've been having difficulty getting the WPF Frame control to resize to it's contents height (HTML).
(edit) the HTML content is 500px, I was expecting the first row to take this height, but the Frame is being clipped to 150px.
I've tried quite a few alterations on this theme:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Frame Grid.ColumnSpan="2"
VerticalAlignment="Bottom"
HorizontalContentAlignment="Stretch" VerticalContentAlignment="Top"
NavigationUIVisibility="Hidden"
Source="..\My Web Sites\test.html" />
<Button Grid.Row="1"
Width="160" Height="50"
HorizontalAlignment="Center" VerticalAlignment="Center"
Content="Book Todays Events" />
<DockPanel Grid.Row="1" Grid.Column="1"
HorizontalAlignment="Center">
<Button Width="160" Height="50"
DockPanel.Dock="Bottom"
HorizontalAlignment="Right"
Content="Select Date" />
<Border Width="350"
HorizontalAlignment="Center"
Background="Gray">
<TextBlock Text="Calendar" />
</Border>
</DockPanel>
</Grid>
I've tried swapping out the Frame for a ContentControl with 500px of content which worked fine, so I'm not sure what the problem is...
The HTML is a static height, and won't change at runtime, however the client will be able to alter it so I don't wan't to define a static height or hack into the HTML to find a height.
How do you expect the height to adjust when the size is auto? Auto means it will adjust to the size of the content. If the HTML is a static height then the row will be that static height. Is that the behavior you are getting? If you want each row to get half the screen height then use *.

WPF Element Binding With Dynamically Generated UI Elements

I have a page in which I have a grid with 2 columns, one accommodating 80* width and the other accommodating 20*. Beneath the grid is a stack panel to which I load UI elements (child stack panels) at runtime.
My objective is to bind the widths of the stackpanels to the columns of the grid. This works perfectly and the stackpenels resize if the dynamic content is mocked to be static in the design view. But when the application is run, the bindings fail and the widths are not bound.
Is there any way to refresh the bindings so that I can notify the stackpanels to refer the widths of the grid and configure its's size?
Updated:
This is what my XAML looks like:
<Page x:Class="WPFTestApp.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid x:Name="resizeGrid"
Grid.Column="0" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="leftColumn"
Width="80*" />
<ColumnDefinition x:Name="rightColumn"
Width="20*" />
</Grid.ColumnDefinitions>
</Grid>
<StackPanel x:Name="contentPanel"
Grid.Column="0" Grid.Row="0" >
<!-- Dynamic StackPanels are added here -->
</StackPanel>
</Grid>
</Page>
In my code, I create StackPanel elements and add it to the contentPanel by saying:
contentPanel.Children.Add(...);
Unfortunately, I HAVE to use StackPanels here. :-(
The markup of a dynamically created StackPanel element is as follows (note that I use a Binding to the grid already in the XAML):
<StackPanel x:Name="element01"
Orientation="Horizontal"
Width="{Binding ElementName=resizeGrid, Path=ActualWidth}" >
<StackPanel x:Name="leftPanel"
Orientation="Vertical"
Width="{Binding ElementName=leftColumn, Path=ActualWidth}">
<!-- Content goes here -->
</StackPanel>
<StackPanel x:Name="rightPanel"
Orientation="Vertical"
Width="{Binding ElementName=rightColumn, Path=ActualWidth}">
<!-- Content goes here -->
</StackPanel>
</StackPanel>
The XAML code for my dynamic StackPanel elements are generated through an XSLT transformation
Note the xmlns:x namespace dynamic StackPanel. This also has to be done because of it being generated through XSLT
As far as I know setting the Width of a StackPanel with Orientation="Horizontal" will have no effect. The size of a StackPanel does not exceed the size of its content in its oriented direction.
Why do you "HAVE" to use StackPanels here? You almost certainly want DockPanels, given your objective. You won't have to bind or set anything, because the DockPanel will fill the cell automatically.
Try binding the ActualWidth instead of Width.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid x:Name="resizeGrid"
Grid.Column="0" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="leftColumn"
Width="{Binding ElementName=contentPanel, Path=ActualWidth}" />
<ColumnDefinition x:Name="rightColumn"
Width="*" />
</Grid.ColumnDefinitions>
</Grid>
<StackPanel x:Name="contentPanel"
Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" >
<StackPanel Background="Yellow" Width="100" Height="25" />
<StackPanel Background="Green" Width="120" Height="25" />
<StackPanel Background="Red" Width="140" Height="25" />
<TextBlock Background="Gray" Text="{Binding ElementName=contentPanel, Path=ActualWidth}" />
</StackPanel>
</Grid>
The following changes I have done above:
1) Set the leftColumn to the ActualWidth of the contentPanel
2) Set the rightColumn to *
3) contentPanel HorizontalAlignment should be changed other then Stretch. Here I have changed it to Left
HTH
I found a solution for this issue. (Sorry for the late response)
What I did was, I cut and pasted the "resizeGrid" Grid control into the "contentPanel" Stackpanel.
As I mentioned above, the contents within the contentPanel are generated through an XSLT transformation and this surely creates a namespace reference issue. I noticed "element not found..." message in the Output window whenever this Window is loaded - this proved me right.
Inserting the "resizeGrid" into the "contentPanel" helped because then both the controls are within the same namespace and can be referenced for a PropertyBinding using "ElementName" attribute.
Thank you for your support! :-)

WPF - How to right align a textblock inside a horizontally oriented stackpanel?

This should be so simple - I've been hitting my head against my desk for so long trying to make a seemlingly simple task work (makes me feel like WPF is un-intuitive or buggy)...
In any case, I've got a Stackpanel which is set to horizontal orientation. Inside it I've got two TextBlocks. I want the 2nd one to display it's text to the right.
How do I accomplish it?
Doing all this reminds me why I walked away from Silverlight. :p
You need to use a DockPanel if you don't want all elements to be stacked like the StackPanel do. To cause the second TextBlock to right-align, you can add an extra dummy TextBlock to fill the area between them:
<DockPanel>
<TextBlock>Left text</TextBlock>
<TextBlock DockPanel.Dock="Right">Right text</TextBlock>
<TextBlock />
</DockPanel>
Or you can use the TextAlignment attribute:
<DockPanel>
<TextBlock>Left text</TextBlock>
<TextBlock TextAlignment="Right">Right text</TextBlock>
</DockPanel>
It can be archived very easily by using grid as I've got the same problem :)
<Grid>
<TextBlock>Left text</TextBlock>
<TextBlock TextAlignment="Right">Right text</TextBlock>
</Grid>
In light of your comments, here is another example showing a couple of ways of accomplishing what you want, Grid layout and DockPanel layout. From the sounds of it, the DockPanel layout is probably what you're looking for. If this doesn't work, you may need to provide a clearer description of your desired layout and properties.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.45*" />
<RowDefinition Height="0.05*" />
<RowDefinition Height="0.45*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<!-- note: you don't need to declare ColumnDefintion
widths here; added for clarity. -->
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Background="Tomato"
TextWrapping="Wrap">I'm on the left</TextBlock>
<TextBlock
Grid.Column="1"
Background="Yellow"
TextAlignment="Right"
TextWrapping="Wrap">I'm on the right</TextBlock>
</Grid>
<Grid Grid.Row="1" Background="Gray" />
<DockPanel Grid.Row="2">
<TextBlock
DockPanel.Dock="Left"
Background="Tomato"
TextWrapping="Wrap">I'm on the left</TextBlock>
<TextBlock
DockPanel.Dock="Right"
Background="Yellow"
TextAlignment="Right"
TextWrapping="Wrap">I'm on the right</TextBlock>
</DockPanel>
</Grid>
</Page>

WPF TextBlock Padding is cutting off text

I have a TextBlock in a Grid with its Padding attribute set to 5. Sometimes the last character is cut off, depending on what string the Text property is set to.
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SomeClass">
<ScrollViewer Padding="5" VerticalScrollBarVisibility="Auto">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label
Grid.Row="0" Grid.Column="0"
Content="SomeLabel"
HorizontalAlignment="Right"
HorizontalContentAlignment="Right"
VerticalAlignment="Center" />
<TextBlock
Grid.Row="0" Grid.Column="1"
HorizontalAlignment="Left"
Padding="5"
Text="0x0F"
TextWrapping="Wrap"
VerticalAlignment="Top" />
</Grid>
</ScrollViewer>
</UserControl>
When the Text is set to 0x0F the F is not visible. When it is set to 0xAB the string displays just fine. Setting the Padding to 0 also makes the string display just fine.
What you describe is obviously a layout bug in WPF (probably in the TextBlock). Whether or not the last letter is wrapped (and cut off) seems to depends on the actual width of the string and the size of the last letter in respect to the size of the padding.
I suggest you report the bug here.
To work around this issue you can use the following code (just put a border around you textblock and set the padding there instead):
<Border Padding="5" Grid.Row="0" Grid.Column="1">
<TextBlock HorizontalAlignment="Left"
Text="0x0F" TextWrapping="Wrap"
VerticalAlignment="Top" />
</Border>
Make the column of the grid that contains textblock auto size like this
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.COlumn="0" Text="{Binding Path=SomeViewModelProperty}" />
</Grid>
If you set the height on the TextBlock to 100, does the F then get wrapped?
Just increase the Height of the ComboBoxItem , it should solve the problem.

Resources