Is it easily possible to specify a margin and/or padding for rows or columns in a WPF Grid?
I could of course add extra columns to space things out, but this seems like a job for padding/margins (it will give much simplier XAML). Has someone derived from the standard Grid to add this functionality?
RowDefinition and ColumnDefinition are of type ContentElement, and Margin is strictly a FrameworkElement property. So to your question, "is it easily possible" the answer is a most definite no. And no, I have not seen any layout panels that demonstrate this kind of functionality.
You can add extra rows or columns as you suggested. But you can also set margins on a Grid element itself, or anything that would go inside a Grid, so that's your best workaround for now.
Use a Border control outside the cell control and define the padding for that:
<Grid>
<Grid.Resources >
<Style TargetType="Border" >
<Setter Property="Padding" Value="5,5,5,5" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Grid.Column="0">
<YourGridControls/>
</Border>
<Border Grid.Row="1" Grid.Column="0">
<YourGridControls/>
</Border>
</Grid>
Source:
Original Source
and from Way Back Machine
You could use something like this:
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Padding" Value="4" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
Or if you don't need the TemplateBindings:
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Padding="4">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Thought I'd add my own solution because nobody yet mentioned this. Instead of designing a UserControl based on Grid, you can target controls contained in grid with a style declaration. Takes care of adding padding/margin to all elements without having to define for each, which is cumbersome and labor-intensive.For instance, if your Grid contains nothing but TextBlocks, you can do this:
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="10"/>
</Style>
Which is like the equivalent of "cell padding".
I am surprised I did not see this solution posted yet.
Coming from the web, frameworks like bootstrap will use a negative margin to pull back rows / columns.
It might be a little verbose (albeit not that bad), it does work and the elements are evenly spaced and sized.
In the example below I use a StackPanel root to demonstrate how the 3 buttons are evenly spaced using margins. You could use other elements, just change the inner x:Type from button to your element.
The idea is simple, use a grid on the outside to pull the margins of elements out of their bounds by half the amount of the inner grid (using negative margins), use the inner grid to evenly space the elements with the amount you want.
Update:
Some comment from a user said it doesn't work, here's a quick video demonstrating: https://youtu.be/rPx2OdtSOYI
<StackPanel>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Grid}">
<Setter Property="Margin" Value="-5 0"/>
</Style>
</Grid.Resources>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="10 0"/>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="Btn 1" />
<Button Grid.Column="1" Content="Btn 2" />
<Button Grid.Column="2" Content="Btn 3" />
</Grid>
</Grid>
<TextBlock FontWeight="Bold" Margin="0 10">
Test
</TextBlock>
</StackPanel>
Edited:
To give margin to any control you could wrap the control with border like this
<!--...-->
<Border Padding="10">
<AnyControl>
<!--...-->
You could write your own GridWithMargin class, inherited from Grid, and override the ArrangeOverride method to apply the margins
I did it right now with one of my grids.
First apply the same margin to every element inside the grid. You can do this mannualy, using styles, or whatever you like. Lets say you want an horizontal spacing of 6px and a vertical spacing of 2px. Then you add margins of "3px 1px" to every child of the grid.
Then remove the margins created around the grid (if you want to align the borders of the controls inside the grid to the same position of the grid). Do this setting a margin of "-3px -1px" to the grid. That way, other controls outside the grid will be aligned with the outtermost controls inside the grid.
I ran into this problem while developing some software recently and it occured to me to ask WHY? Why have they done this...the answer was right there in front of me. A row of data is an object, so if we maintain object orientation, then the design for a particular row should be seperated (suppose you need to re-use the row display later on in the future). So I started using databound stack panels and custom controls for most data displays. Lists have made the occasional appearance but mostly the grid has been used only for primary page organization (Header, Menu Area, Content Area, Other Areas). Your custom objects can easily manage any spacing requirements for each row within the stack panel or grid (a single grid cell can contain the entire row object. This also has the added benefit of reacting properly to changes in orientation, expand/collapses, etc.
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<custom:MyRowObject Style="YourStyleHereOrGeneralSetter" Grid.Row="0" />
<custom:MyRowObject Style="YourStyleHere" Grid.Row="1" />
</Grid>
or
<StackPanel>
<custom:MyRowObject Style="YourStyleHere" Grid.Row="0" />
<custom:MyRowObject Style="YourStyleHere" Grid.Row="1" />
</StackPanel>
Your Custom controls will also inherit the DataContext if your using data binding...my personal favorite benefit of this approach.
I had similar problem recently in two column grid, I needed a margin on elements in right column only. All elements in both columns were of type TextBlock.
<Grid.Resources>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource OurLabelStyle}">
<Style.Triggers>
<Trigger Property="Grid.Column" Value="1">
<Setter Property="Margin" Value="20,0" />
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
One possibility would be to add fixed width rows and columns to act as the padding / margin you are looking for.
You might also consider that you are constrained by the size of your container, and that a grid will become as large as the containing element or its specified width and height. You could simply use columns and rows with no width or height set. That way they default to evenly breaking up the total space within the grid. Then it would just be a mater of centering your elements vertically and horizontally within you grid.
Another method might be to wrap all grid elements in a fixed with single row & column grid that has a fixed size and margin. That your grid contains fixed width / height boxes which contain your actual elements.
in uwp (Windows10FallCreatorsUpdate version and above)
<Grid RowSpacing="3" ColumnSpacing="3">
Though you can't add margin or padding to a Grid, you could use something like a Frame (or similar container), that you can apply it to.
That way (if you show or hide the control on a button click say), you won't need to add margin on every control that may interact with it.
Think of it as isolating the groups of controls into units, then applying style to those units.
As was stated before create a GridWithMargins class.
Here is my working code example
public class GridWithMargins : Grid
{
public Thickness RowMargin { get; set; } = new Thickness(10, 10, 10, 10);
protected override Size ArrangeOverride(Size arrangeSize)
{
var basesize = base.ArrangeOverride(arrangeSize);
foreach (UIElement child in InternalChildren)
{
var pos = GetPosition(child);
pos.X += RowMargin.Left;
pos.Y += RowMargin.Top;
var actual = child.RenderSize;
actual.Width -= (RowMargin.Left + RowMargin.Right);
actual.Height -= (RowMargin.Top + RowMargin.Bottom);
var rec = new Rect(pos, actual);
child.Arrange(rec);
}
return arrangeSize;
}
private Point GetPosition(Visual element)
{
var posTransForm = element.TransformToAncestor(this);
var areaTransForm = posTransForm.Transform(new Point(0, 0));
return areaTransForm;
}
}
Usage:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:GridWithMargins ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Rectangle Fill="Red" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Rectangle Fill="Green" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Rectangle Fill="Blue" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</local:GridWithMargins>
</Grid>
</Window>
Sometimes the simple method is the best. Just pad your strings with spaces. If it is only a few textboxes etc this is by far the simplest method.
You can also simply insert blank columns/rows with a fixed size. Extremely simple and you can easily change it.
Related
I need to remove the space occupied by a Grid.Row. I am able to collapse (remove) the control I have placed in Grid.Row, but since RowDefinition has fixed size (height) even after removing the child control I still get to see a blank row.
Is there a way to Collapse a RowDefinition/Grid.Row?
Thanks for your interest.
You could have set RowDefinition.Height="Auto" and could have assigned fixed height to the actual visual in that row. This way when the visual is visibly collapsed, the row does not occupy the fixed height that was assigned to the row definition.
Setting RowDefinition.Height ="Auto" is not suitable for all cases, as often we want * sizing of our rows.
Rather than dynamically/programatically adding and removing rows from the list, it is easier and safer to stretch the first rows contents over the next row/s.
This can be done by using a DataTrigger to set Grid.RowSpan on the first item on the grid. Below is a complete example - just paste it into a new WPF window to see it in action.
<Grid>
<Grid.Resources>
<BooleanToVisibilityConverter x:Key="visConverter"></BooleanToVisibilityConverter>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Orange">
<Grid.Style>
<Style TargetType="Grid">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=toggle1, Path=IsChecked}" Value="False">
<Setter Property="Grid.RowSpan" Value="3"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>
<GridSplitter Grid.Row="1" ResizeBehavior="PreviousAndNext" HorizontalAlignment="Stretch" Height="3"
Visibility="{Binding ElementName=toggle1, Path=IsChecked, Converter={StaticResource visConverter}}"></GridSplitter>
<Grid Name="bottomGrid" Grid.Row="2" Background="LightBlue"
Visibility="{Binding ElementName=toggle1, Path=IsChecked, Converter={StaticResource visConverter}}">
</Grid>
<ToggleButton Name="toggle1" VerticalAlignment="Top">Hide/Show</ToggleButton>
</Grid>
It's absolutely okay to apply a style with triggers to your RowDefinition for the row you want to collapse. This can help when you have star values for your heights.
The following might be useful if you wanted to hide a results section before results existed (i.e. a zero-count ObservableCollection), for example.
<RowDefinition>
<RowDefinition.Style>
<Style>
<Setter Property="RowDefinition.Height" Value="2*"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Results.Count}" Value="0">
<Setter Property="RowDefinition.Height" Value="0"/>
</DataTrigger>
</Style.Triggers>
</Style>
</RowDefinition.Style>
</RowDefinition>
You can see here an example of manipulating Rows and Columns in a Grid. Even though the documentation is for .Net (WPF) it is still relevant for WP7/Silverlight.
I personally would think twice before using a Grid in this manner. May be, whatever you are trying can be achieved using a stackpanel or any other out of the box container controls.
Set Name for your grid first. Initially, set the row heights via XAML attribute:
<Grid Name="GridSize">
<Grid.RowDefinitions>
<RowDefinition Height="3*"></RowDefinition>
<RowDefinition Height="1*"></RowDefinition>
<RowDefinition Height="2*"></RowDefinition>
</Grid.RowDefinitions>
<Grid Name="A" Grid.Row="0""></Grid>
<Grid Name="B" Grid.Row="1""></Grid>
<Grid Name="C" Grid.Row="2""></Grid>
</Grid>
When you want to collapse a RowDefinition:
A.Visibility = Visibility.Collapsed;
GridSize.RowDefinitions[0].Height = new GridLength(0);
When you want to make it visible again:
A.Visibility = Visibility.Visible;
GridSize.RowDefinitions[0].Height = new GridLength(3, GridUnitType.Star);
A simple solution (use the height that you know your controls will expand to):
<RowDefinition MaxHeight="30"/>
Then make sure all the controls inside that Row will use Visibilitty="Collapsed"
This worked for me, as I only needed to set the flag to Collapse / Visible once only, not sure how this will work if you would like to toggle visibility at run time.
I am using the Chart control of WPF Toolkit February 2010 release. The chart takes up lots of space relative to the plot area.
How do I control the margin around the plot area and title of the chart. This way, I can arrange the 10 charts I need in a grid without having to use so much space on the screen.
Thanks,
sprite.
I found an answer to a similar question in the WPF Toolkit discussion boards and thought I'd share the knowledge.
The only solution currently available is to style the chart myself. So basically, I took the original style definition from the source code of the toolkit and I modified it to meet my needs. I also used this to remove the legend completely.
<Grid.Resources>
<!-- chart style modified from WPFToolkit\DataVisualization\Themes\generic.xaml -->
<Style TargetType="charts:Chart">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="charts:Chart">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<dataVis:Title Content="{TemplateBinding Title}" Style="{TemplateBinding TitleStyle}" Margin="1"/>
<!-- Use a nested Grid to avoid possible clipping behavior resulting from ColumnSpan+Width=Auto -->
<Grid Grid.Row="1" Margin="5,0,5,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<chartPrmtvs:EdgePanel x:Name="ChartArea" Style="{TemplateBinding ChartAreaStyle}">
<Grid Canvas.ZIndex="-1" Style="{TemplateBinding PlotAreaStyle}" />
<Border Canvas.ZIndex="10" BorderBrush="#FF919191" BorderThickness="1" />
</chartPrmtvs:EdgePanel>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
This template removes margins to a bare minimum around the title and plot area and also removes the legend. I then used this in a user control suited to my needs and reused it many times over.
The following namespaces were defined in the header of the control:
xmlns:dataVis="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit"
xmlns:chartPrmtvs="clr-namespace:System.Windows.Controls.DataVisualization.Charting.Primitives;assembly=System.Windows.Controls.DataVisualization.Toolkit"
xmlns:charts="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
Enjoy!
i have a question regarding some complex data-binding.
I want to be able to update a grid (which has the property "IsItemsHost" set to true)
dynamically whenever a data-binding occurs.
Actually i am using a CustomControl which is an ItemsControl and this
has the Grid in its ControlTemplate.
To be more specific, i bind the grid to some items and i want to
change the number of grid rows depending on these items,
add something like a header (one row containing some text),
and set the items' Grid.Row and Grid.Column using some custom logic.
What is the easiest way to apply such behaviour
whenever the bound data is updated?
Do i have to use a viewmodel that also contains the header data?
Thanks in advance.
Code of the CustomControl Generic.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TimeTableControl">
<Style TargetType="{x:Type local:TimeTableControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TimeTableControl}">
<Border Width="Auto" Height="Auto" BorderBrush="#FF4B5A9B" BorderThickness="4" CornerRadius="4" Margin="2" Padding="0" Background="White">
<Grid Width="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="0.1*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Viewbox>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DayCaption}"/>
</Viewbox>
<Border Grid.Row="1" BorderThickness="0,2,0,0" BorderBrush="#FF4B5A9B">
<Grid Name="ContentGrid" IsItemsHost="True">
</Grid>
</Border>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Grid is used for layout. If you have a changing number of items in some collection, what you really want is ItemsControl, or more specific ListBox (if you want item selection, etc).
If you still want Grid-like behavior of individual rows, you may want to define a Grid in ItemsControl.ItemTemplate and play with Grid.IsSharedSizeScope at ItemsControl level. Alternatively, you may just use ListView instead to get the grid look and item selection in a package.
Update: I got it working by creating a custom panel that uses MeasureOverride and ArrangeOverride to update itself. This lets me adjust the panel to the children and I don't even need to use a grid. This also makes the control lookless.
The default behavior of the WPF Tabcontrol is to place the Tab Headers adjacent to each other, without any empty space in between. What if I wanted to specify a gap between the headers? Do I have to define a control template for this? I'm relatively new to WFP and any help is appreciated.
Thanks
I believe you will need to define a custom control template for the TabItem, maybe even one for the TabControl. Here is an example of a TabItem that uses a spacer for some separation.
<Style
x:Key="SpacedTab"
TargetType="{x:Type TabItem}">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type TabItem}">
<Border
x:Name="Spacer"
Width="Auto"
Height="Auto"
Padding="0 0 5 0"
Margin="0 0 0 0"
BorderBrush="Transparent"
BorderThickness="0">
<Border
x:Name="Border"
MinWidth="150"
Width="Auto"
Height="30"
Background="Gray"
BorderBrush="DarkGray"
BorderThickness="0,0,0,0"
CornerRadius="6,6,0,0"
Cursor="Hand"
VerticalAlignment="Bottom">
<ContentPresenter
x:Name="ContentSite"
TextElement.FontSize="10pt"
TextElement.FontFamily="Arial"
TextElement.Foreground="Black"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="8,3,8,3"
Width="Auto"
Height="Auto" />
</Border>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Hopefully that is a nudge in the right direction; you will still need to add that as a style resource and reference it from your TabControl -> TabItem.
It is easy to add space by doing it in the designer. Select the Tab you want to move, by starting with the rightmost tab. Then hold ctrl and use the right arrow key to move the tab to the right. Do the same with the rest of the tabs. Then you can manually adjust the margin in the xaml code.
I'm currently working out the layout of a WPF Application and seem to have it a bit of a snag in the layout of one of my controls. This control is a dynamically sizing, so it should fit the size of the viewport it's a part of. The problem I'm running into is a very visual problem, so I'll do my best to describe it. Here's what it looks like at the moment:
alt text http://gallery.me.com/theplatz/100006/Capture/web.png?ver=12472534170001
The area underneath each of the "Col N Row X" headers is a TextBlock where text of varying length will be placed. To make the TextBlock actually wrap, I found a solution here on stackoverflow that said to bind the width of the textblock to that of the column. Here's a snippet of the Grid definition along with the definition for the first column:
<!-- Change Detail Contents Grid -->
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="270" Width="2*" />
<ColumnDefinition MinWidth="160" Width="*" />
<ColumnDefinition MinWidth="160" Width="*" />
<ColumnDefinition MinWidth="160" Width="*" />
</Grid.ColumnDefinitions>
<!--
We bind the width of the textblock to the width of this border to make sure things resize correctly.
It's important that the margin be set to 1 larger than the margin of the textblock or else you'll end
up in an infinate loop
-->
<Border Grid.Column="0" Margin="6" Name="FirstBorder" />
<Border Grid.Column="0" BorderThickness="0,0,1,0" BorderBrush="{DynamicResource ColumnBorderBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<Border Style="{DynamicResource DetailHeadingBorder}">
<TextBlock Text="Col 1 Row 1" Style="{DynamicResource DetailHeadingText}" />
</Border>
<TextBlock Text="{Binding IsReason, ElementName=ChangeDetailRoot}" Style="{DynamicResource DetailText}" Width="{Binding ActualWidth, ElementName=FirstBorder}" />
</StackPanel>
<StackPanel Grid.Row="1">
<Border Style="{DynamicResource DetailHeadingBorder}">
<TextBlock Text="Col 1 Row 2" Style="{DynamicResource DetailHeadingText}" />
</Border>
<TextBlock Text="{Binding WasReason, ElementName=ChangeDetailRoot}" Style="{DynamicResource DetailText}" Width="{Binding ActualWidth, ElementName=FirstBorder}" />
</StackPanel>
</Grid>
</Border>
</Grid>
Everything resizes fine when the window/viewport width is increasing. The problem become apparent when the width is decreased. If you suddenly go from maximized to the original size, all of the columns "dance" back to their specified size. What I mean by this is that you can watch each column reduce in size, as it's proportionally resized back to its smaller size. What I've found is that this is directly caused by
Width="{Binding ActualWidth, ElementName=FirstBorder}"
on each of the TextBlocks. The problem also become noticeably worse the more of these controls are on the screen at one time. But, without that line, the text inside each of the TextBlocks will continue to grow to the right the more text is added instead of wrapping down in the column.
Is there a better way to accomplish what I'm trying to accomplish? Using HTML/CSS, this would be a fairly simple thing to accomplish. I've spent hours Googling and looking through stackoverflow for an answer to this question.
I come from a heavy background of HTML/CSS, so if this isn't something that WPF should be good at, please let me know.
I hate to answer my own question, but it appears that I may have found out what I was doing incorrectly. Since it's been so long since the original question was asked, I cannot remember every step I attempted to take, but this is what I do know. The style on each textblock was set as such:
<Style x:Key="DetailText" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="TextAlignment" Value="Center" />
<Setter Property="Margin" Value="5,5,5,5" />
</Style>
At that time, I'm assuming that did not produce the desired results and therefore I had to bind the width of the textblock to that of the column. In playing around today, I changed the style to the following (note the different HorizontalAlignment) and removed the bindings and found out that my problem had been resolved:
<Style x:Key="DetailText" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="TextAlignment" Value="Center" />
<Setter Property="Margin" Value="5,5,5,5" />
</Style>
I apologize if you've tried this, but does setting TextBlock.TextWrapping to "Wrap" not accomplish your goal?
I'm guessing that will get rid of the need for the bind-to-width stuff you're doing, as the Grid will take care of the resizing. (That is probably what is happening now: The Grid is laying out the controls as it shrinks, and the binding to width is changing the size slightly, causing the dancing.)
[Update]
I tried to duplicate the behavior you're seeing, but it works fine for me. I made a simple style for the TextBlocks like so:
<Style x:Key="DetailText" TargetType="{x:Type TextBlock}">
<Setter Property="TextBlock.TextWrapping" Value="Wrap"/>
</Style>
And I didn't have any of your other dynamic resources (DetailHeadingBorder, DetailHeadingText, or ColumnBorderBrush), so everything was black and white (fine).
Maybe you just have a really old graphics card and it's rendering things in software? Or it has to do with your styles.
I hope I didn't misinterpret your question, but I don't see the need for binding TextBlock.Width?
This xaml seems to work correctly:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="270"
Width="2*" />
<ColumnDefinition MinWidth="160"
Width="*" />
<ColumnDefinition MinWidth="160"
Width="*" />
<ColumnDefinition MinWidth="160"
Width="*" />
</Grid.ColumnDefinitions>
<!-- We bind the width of the textblock to the width of this border to make sure things resize correctly.
It's important that the margin be set to 1 larger than the margin of the textblock or else you'll end
up in an infinate loop -->
<Border Grid.Column="0"
BorderThickness="0,0,1,0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<Border>
<TextBlock Text="Col 1 Row 1" />
</Border>
<TextBlock TextWrapping="Wrap"
Text="gfege dfh lh dfl dhliöslghklj h lglsdg fklghglfg flg lgheh" />
</StackPanel>
<StackPanel Grid.Row="1">
<Border>
<TextBlock Text="Col 1 Row 2" />
</Border>
<TextBlock Text="Massor av text som blir en wrappning i slutändan hoppas jag"
TextWrapping="Wrap" />
</StackPanel>
</Grid>
</Border>
</Grid>
I just removed the width bindings, added TextWrapping (which you probably had in a style), and removed the border named "FirstBorder" as well.