Setting width of a TextBlock vs a Grid - wpf

If there's a TextBlock inside a Grid, what's the best way (performance wise) to set its width and height?
Is setting them in the TextBlock's properties will be better than setting it as Grid's properties?
basically what I'm asking is which one of the following is better :
<Grid Width="200" Height="200">
<TextBlock />
</Grid>
vs
<Grid>
<TextBlock Width="200" Height="200"/>
</Grid>

<Grid Width="200" Height="200">
<TextBlock />
</Grid>
Using a Grid purely to constrain a TextBox is not really a good way to set the width of the TextBox. A Grid is more for laying out multiple controls. However this is perfectly acceptable:
<Grid Width="200" Height="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1" HorizontalAlignment="Stretch" Margin="5,0" />
</Grid>
This is along the same lines as what #Ahmed suggested.
Generally with a XAML layout the recommendation is to use a proportional layout rather than fixed sizes, so that your UI can be resized correctly with minimal oversight from any of your code. This means it is good to let the parent element dictate the size as much as possible, only used fixed sizes where you must. (Setting MinWidth/MaxWidth/etc is fine, just try to avoid explicitly setting Width where possible, the same goes for the Height properties).

I Really don't understand specifically what you are asking about !
But I really like to set my Grid to be stretched as Window and set my TextBox Width & Height to Auto Or NAN ,, then define special margins & alignments to my Textbox

In the Layout System article on MSDN there is a small section on performance but there is also a dedicated article on optimizing performance of the layout and design. Maybe there is something helpful in there.
It seems to me that this documentation does not make any claims about this issue though, it probably does not matter or the difference is negligibly small.

I don't have any stats to back this up but since WPF's rendering/layout engine works by first measuring the child elements of everything, one would assume if you manually define the size of a child element it would have a marginal effect.
In this scenario, if all you're doing is wrapping a single TextBlock element, you might be better off using something like a <Border>. If there's multiple elements, see if you can use a <StackPanel>.

Related

Grid and StackPanel, which has the better performance?

Let's read these codes, I've defined two similar UserControls in a Windows Phone 8 project and I really want to which of them is better. I've check the profiling, it seems they are almost the same.
UserControl 1, using grid's property to design my layout.
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}" Height="108">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Rectangle Grid.RowSpan="2" Grid.Row="0" Height="108" Width="54" Fill="Blue"></Rectangle>
<TextBlock Grid.Row="0" Grid.Column="1" Text="Caption" Style="{StaticResource PhoneTextExtraLargeStyle}"></TextBlock>
<TextBlock Grid.Row="1" Grid.Column="1" Text="URLURLURLURLURLURL" Style="{StaticResource PhoneTextSmallStyle}"></TextBlock>
</Grid>
UserControl 2, using StackPanel to design my layout.
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}" Height="108">
<StackPanel Orientation="Horizontal">
<Rectangle Height="108" Width="54" Fill="Red"></Rectangle>
<StackPanel Orientation="Vertical">
<TextBlock Text="Caption" Style="{StaticResource PhoneTextExtraLargeStyle}"></TextBlock>
<TextBlock Text="URLURLURLURLURLURL" Style="{StaticResource PhoneTextSmallStyle}"></TextBlock>
</StackPanel>
</StackPanel>
</Grid>
It looks like the basic layout is the same. But when I use XAML Spy to analyse the Visualizing tree, UserControl 1 has less nodes, but it costs a little more memory. Why?
You may be interested in the answers to this question: In what order are Panels the most efficient in terms of render time and performance?
The short answer is it depends on how many children the panels have, and how those elements are sized and positioned. But in most cases, a StackPanel will be more efficient than a Grid as it has both a faster measure and arrangement pass.
To quote from the accepted answer:
Grid
Defines a flexible grid area that consists of columns and rows.
This can be the most performance intensive panel if proportional
sizing or auto sizing is used. Calculating child item size can be a
complex combination of the native size of the item and the layout
specified by the grid. Layout is also the most complicated of all the
panels. Slow to medium performance for the measure pass and slow to
medium performance for the arrangement pass.
StackPanel
Arranges child elements into a single line that can be oriented horizontally or vertically.
The StackPanel measures its children using either native or relative
sizing in the opposite direction from its orientation and native
sizing in the direction of its orientation (alignment does nothing in
this direction). This makes it a mid-level performer in this area. The
Arrangement pass is simply, just laying out the items in order.
Probably the second-best performance for this pass. Medium performance
for the measure pass and fast performance for the layout pass.
Also in regards to memory consumption, both objects are different and take up different amounts of memory, and a Grid has RowDefinitions and ColumnDefinitions, so it actually contains more objects than your StackPanel

Setting width in a data template based on the size of a parent control

I am using a telerik TreeView in WPF, and I'm using a HierarchicalDataTemplate to show the nodes. Nodes represent matched items - which can be left only, right only, equal or inequal (a tree based comparison).
I am currently using a DataTemplateSelector to select from one of four templates, which all look similar to the following:
<HierarchicalDataTemplate x:Key="EqualTreeItemTemplate" ItemsSource="{Binding}">
<Grid Name="rowGrid" HorizontalAlignment="Stretch" Height="Auto" d:DataContext="{d:DesignInstance Carbon:ICarbonComparisonPair }">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="16" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Path Data="F1M574.042,314.611L533.8,344.398 522.251,328.798 515.235,333.988 526.786,349.593 526.782,349.596 531.978,356.603 579.235,321.622 574.042,314.611z" Stretch="Uniform" Fill="#FF000000" Width="16" Height="16" VerticalAlignment="Center" Margin="0,0,0,0" />
<TextBlock Grid.Column="1" Text="{Binding ObjectName}" Style="{StaticResource ObjectNameStyle}" Margin="4,0,0,0" />
<TextBlock Grid.Column="2" Text="{Binding ObjectName}" Style="{StaticResource ObjectNameStyle}" Margin="4,0,0,0" />
</Grid>
</HierarchicalDataTemplate>
The problem that I have is that the item content area is a different width based on the level of the tree that the item appears in. This means that the columns that I have don't line up - the text in the right hand column shifts to the right a bit for each level of the tree that you expand.
What I would like to do is specify the right hand grid column's width to be 50% of the size of the tree control as a whole, rather than 50% of the grid's natural area. I thought maybe I could do this with a binding with a RelativeSource, but I just can't seem to make it work. Is there a way to achieve this in XAML, or do I need to resort to code-behind?
If I'm understanding it correctly you want column index 2 to align across all items?
Check out the TreeListView control and see if that gives you what you need.
Silverlight demo here (just so you can see what it looks like - the WPF version is pretty much the same)
[Edit - More info]
The SharedGroupName property on ColumnDefinition is tempting but, thanks to the indent, it won't quite work - you'll end up with all of the content in column 1 or 2 being sized the same, but the pesky indent still throws it off. Check out ListView's View Property. I'm believe it's at least in the same spirit as what Telerik TreeListView is, if not darned similar in implementation.
Here's a decent writeup on how to use it. (Ironically I have that page bookmarked in a folder called "TreeGridList" so apparently at some point I had the idea to do that to accomplish something similar :) )

How to align buttons on opposite sides of window in WPF?

trying first time WPF user. I read through some WPF layout docs but am not getting the hang of the layout of buttons. I'm trying to get the layout below -- where there's a button in the lower left corner and two in the lower right.
Can this be done with a single StackPanel? I tried unsuccessfully with this along with the HorizontalAlignment attributes of the buttons.
Is it more appropriate to be using a 1 row, 2 column grid, with each cell having a StackPanel?
Any suggestions much appreciated, thanks!
Personally, I tend to prefer doing this with a Grid, ie:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Width="100">b1</Button>
<Button Grid.Column="1" Width="100">b2</Button>
<Button Grid.Column="2" Width="100">b3</Button>
</Grid>
This will cause the 2nd & 3rd columns to fit their contents, and the first to fill the rest of the space. If you place each button in the appropriate column, you'll get that layout. (Note that you'll likely want to adjust the sizing and margins on the buttons to get nice spacing, as well.)

How to make text wrap in a WPF TreeViewItem?

This time, my question is as simple as it sounds... how do you get text to wrap in a WPF TreeViewItem?
I have a simple HierarchicalDataTemplate with just one TextBlock in it.
<TextBlock Text="{Binding Value}" TextWrapping="Wrap" />
The text does not wrap.
I tried binding the Width of the TextBlock to the ActualWidth of the TreeView, but although that makes the text wrap, the Width of the TreeViewItem does not fit in the TreeView because the TreeView has Padding. Binding to the ActualWidth of the TreeViewItem has (unsurprisingly) the same effect. Another downside to this is that even the items with little text stretch outside the TreeView bounds.
<TextBlock Text="{Binding Value}" TextWrapping="Wrap" Width="{Binding ActualWidth,
ElementName=TreeView}" />
Surely there must be a better way, like somehow informing the TreeViewItem of the TreeView's bounds... I can't believe it doesn't know automatically. But how can I do this?
UPDATE >>>
Thanks to H.B.'s answer, I managed to change the Grid.ColumnSpan to 2 on the Bd Border he mentioned in the ControlTemplate and it set the width so that the text now wraps nicely. The problem is that I am using this ControlTemplate for other TreeViewItems in other TreeViews where I don't want full width items.
The solution I came up with is simple. I have bound the TreeViewItem.Tag value to the Grid.ColumnSpan property in the ControlTemplate like so:
<Border Grid.ColumnSpan="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}"
Name="Bd" Grid.Column="1" ... />
This allows me to change the Grid.ColumnSpan and therefore the full width or ordinary width behaviour of the TreeViewItem by setting the TreeViewItem.Tag value to either 2 or 1 respectively.
If you look at the default template of TreeViewItems you will see a Grid like this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="19"
Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- ... -->
As you can see the third column takes all available space while the others are on Auto, the header is placed in the second column inside a border:
<Border Name="Bd"
Grid.Column="1"
...
This means that the column will become as large as the header, there is no restriction on it. Thus the header just gets bigger than the TreeView itself.
If you add Grid.ColumnSpan="2" to this Border it will occupy the third column as well, which is restricted by how much space is left, hence the text will wrap; this will however extend the header across the whole width which might look a bit odd when selecting it.
Of course you will also need to disable horizontal scrolling:
<TreeView ScrollViewer.HorizontalScrollBarVisibility="Disabled" ...

restricting the size of wpf dockpanel region

Is there a way you can pin a wpf dockpanel? I have searched on the net and I have not found any functionality that will allow this. What I want is to lock the size of a dockpanel's dock regions. For example I want the right region"s width to stay locked all the time. The only solutions to this that I have seen are 3rd party controls. Does anyone know of a way to restrict the width of these regions? Thanx in advance.
You can set the MaxWidth property of the control you are docking.
According to your additional explanations, you have the following layout:
<DockPanel>
<ItemsControl DockPanel.Dock="Left"/>
<StackPanel DockPanel.Dock="Right"/>
</DockPanel>
The first thing I recommend is to add LastChildFill="False" to the DockPanel so your left and right parts grow unrelated.
Then you have to decide what happens when the number of items in the ItemsControl increase. You can make a horizontal scrollbar appear, make them wrap, and so on.
Yes, I had LastChildFill = "False" already set, plus the my items control is already in a scrollviewer with a horizontal template applied. With this setup the initial layout looks great in the row. The only problem is when the itemscontrol grows too big and hits the right dock, it will always force the right dock to go smaller even though the minwidth is set on the grid that is contained within. Here is an example of my code:
<DockPanel Grid.Row="1" LastChildFill="False">
<!--Horizontal template applied-->
<ScrollViewer DockPanel.Dock="Left">
<ItemsControl/>
</ScrollViewer>
<Grid DockPanel.Dock="Right" MinWidth="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0"/>
<Button Grid.Column="1"/>
</Grid>
</DockPanel>
Thanks for the help . . . any other ideas?

Resources