WPF: Scale Grid without scaling content - wpf

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...

Related

WPF - Align checkbox with datagrid column

I need to position a checkbox above a column in a datagrid, and keep the checkbox aligned with the left edge of the column, even if the columns are resized (or reordered) by the user.
Putting the checkbox in the column header is probably not an option.
The first challenge is knowing when the user is resizing a column.
There is a ColumnHeaderDragStarted event, but I think that is raised when the user drags a column header to reorder it. Does it also apply to a column resize operation?
The next challenge is re-positioning the checkbox as the column is moved. How can the position of the left edge of the column ("Val1", for example) be determined w/r/t to the left edge of the containing grid? I suspect that if that value can be determined, it can be used to position the checkbox.
Thanks for any insights in to this problem --
UPDATE 2
This xaml is providing much of the desired behavior, but the alignment isn't right. If the user move the separator between "Id" and "Val1", the checkbox moves.
The goal, however, is to have the checkbox remain aligned above "Id"; it should move only when the separator between "Name" and "Id" is moved.
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="32" />
<RowDefinition />
</Grid.RowDefinitions>
<DataGrid x:Name="DataGrid"
Grid.Row="1" Grid.Column="0" />
<Canvas Grid.Row="0" Grid.RowSpan="2" >
<CheckBox Content="Check One"
Canvas.Top="10"
Canvas.Left="{Binding Columns[1].ActualWidth, ElementName=DataGrid}" />
</Canvas
</Grid>
UPDATE:
This seems like it might be a useful approach:
https://stackoverflow.com/a/41094009/107037
The challenge of positioning the checkbox still exists, however...
Since someone asked:
Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="32" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<CheckBox Content="Check One" Grid.Column="1" />
<CheckBox Content="Check One" Grid.Column="2" />
<DataGrid x:Name="DataGrid"
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4" ></DataGrid>
</Grid>

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 *.

Display non rectangular shaped TextBlock

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.

What WPF Panel control to use that anchors children to an edge (Concertina effect)?

This (hopefully) is an easy one... I'm trying to find a WPF panel that I can use that when resized keeps all it's vertically aligned children (buttons) offset the same distance from the bottom edge of the panel, so it looks like they are expanding.
The obvious one is to use a dock panel and anchor to the bottom but this doesn't seem to work. Putting more that 2 children in there messes up the alignment and whatever I do I can't get them vertically lined up. I've tried all sorts of panels but have had no joy. I'm assuming it's fairly straightforward but it's stumped me!
Basically I'm trying to get a concertina effect when I click the top button the panel expands and shows all the sub buttons. And when I click the top button again it collapses. I guess I can move each of the children with a storyboard but I have to think all my story needs to do is change the size of the panel and the children maintain their offsets and concertina out...
Any ideas?
Thanks in advance!
If "Basically I'm trying to get a concertina effect" is the essence of your question (Am I right ?) then, did you tried tu use an built-in WPF expander ? It seems to me that you are trying to build up your own...
I believe you can actually use a Canvas and set the Canvas.Top, Left, Right, and Bottom properties of the controls to get the same effect as WinForms and anchor.
<Canvas>
<Button Canvas.Left="30" Canvas.Bottom="10" Content="Button 1" Name="button1" />
<Button Canvas.Left="90" Canvas.Bottom="10" Content="Button 2" Name="button2" />
</Canvas>
Also Grid can do similar:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Button Grid.Row="1" Grid.Column="0" Content="Button 1" Name="button1" Margin="5" />
<Button Grid.Row="1" Grid.Column="1" Content="Button 2" Name="button2" Margin="5" />
</Grid>
I do not quite get what you mean by concertina effect, it could have to do with stretching as well. If you want anchoring you can use a Grid:
<Grid>
<Grid.RowDefinitions>
<RowDefinition /> <!-- Gets all available space i.e. resizes with window -->
<RowDefinition Height="Auto"/> <!-- Sizes to content, always stays at the bottom -->
</Grid.RowDefinitions>
<!-- Resizable content goes in Grid.Row="0" -->
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="5">
<Button Name="ButtonOK" HorizontalAlignment="Right" Width="100" Margin="5" Click="ButtonOK_Click" IsDefault="True">OK</Button>
<Button Name="ButtonCancel" HorizontalAlignment="Right" Width="100" Margin="5" Click="ButtonCancel_Click" IsCancel="True">Cancel</Button>
</StackPanel>
</Grid>

Fixing a listbox's size in WPF

I have a Listbox that's inside a Grid that's inside a user control. That user control is placed in a tab panel that can resize.
The Listbox is defined as:
<ListBox HorizontalAlignment="Left" Margin="12,42,12,12" Name="listBox1" VerticalAlignment="Top" >
This works great as long as my listbox is populated. When it's not populated, it's a square about 4 pixels wide/tall. If it's not full, it shrinks down to fit whatever is in it.
This is not what I'd like. What I would like is for it to always maintain the margins I've defined. My question is in two parts:
1: Why does it behave the way it does?
2: How do I make it behave the way I want?
Thanks.
Since you're placing this on a Grid control, you should actually use it as intended and create the rows and columns and put your ListBox in the correct cell(s).
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="42" />
<RowDefinition />
<RowDefinition Height="12" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="12" />
<ColumnDefinition />
<ColumnDefinition Width="12" />
</Grid.ColumnDefinitions>
<ListBox x:Name="listBox1"
Grid.Row="1" Grid.Column="1">
</ListBox>
</Grid>
It is maintaining the margins but the margins are outside the listbox itself so only change the positioning of the listbox relative to its container.
I'm not sure how you would like it to appear but could set a minimum width/height.
<ListBox HorizontalAlignment="Left" Margin="12,42,12,12"
Name="listBox1" MinHeight="10" MinWidth="100" VerticalAlignment="Top" />
or just remove the alignment settings
<ListBox Margin="12,42,12,12" Name="listBox1" />
if you want the listbox to fill its container.

Resources