Consider the following XAML:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Content="Button" HorizontalAlignment="Left"/>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Content="B" Margin="5"/>
<Button Content="Button" Grid.Column="1" Margin="5"/>
</Grid>
</Grid>
In the above, all ColumnDefinition values except one use the default value for Width, which is "*", i.e. "star sizing". The one exception is the column containing the nested Grid control, which is set to "Auto".
The way I expect this to work is as follows:
The outer Grid sizes the second column according to the needs of its content, and then assigns the remaining width of the control to the first column.
The inner Grid distributes its available space evenly to the two columns. After all, they both are set to use star sizing, and star sizing is supposed to set the GridLength property (width, in this case) to a weighted distribution of available space. The minimum layout size for this inner Grid (needed for the outer Grid to compute the width of its second column) is the sum of evenly-distributed-width, star-sized columns (i.e. in this case, two times the width of the column with the widest content).
But instead, the column widths for the nested grid are set according to the computed minimum size of each button, with no apparent weighted relationship between the two star-sized columns (gridlines are shown for clarity):
It works as expected if I don't have the outer grid, i.e. just make the inner grid the only grid in the window:
The two columns are forced to be the same size, and then of course the left-hand button is stretched to fit the size of its containing cell (which is what I want…the end goal is for those two buttons to have the same width, with the grid columns providing the layout to accomplish that).
In this particular example, I can use UniformGrid as a work-around, to force even distribution of column widths. This is how I want it actually to look (UniformGrid doesn't have a ShowGridLines property, so you just have to imagine the imaginary line between the two right-most buttons):
But I really would like to understand more generally how to accomplish this, so that in more complex scenarios I would be able to use star-sizing in a nested Grid control.
It seems that somehow, being contained within the cell of another Grid control is changing the way that star sizing is computed for the inner Grid control (or preventing star sizing from having any effect at all). But why should this be? Am I missing (yet again) some esoteric layout rule of WPF that explains this as "by design" behavior? Or is this simply a bug in the framework?
Update:
I understand Ben's answer to mean that star-sizing should be distributing only the left-over space after the minimum sizes for each column has been accounted for. But that is not what one sees in other scenarios.
For example, if the column containing the inner grid has been sized explicitly, then using star-sizing for the inner grid's columns results in the columns being sized evenly, just as I'd expect.
I.e. this XAML:
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<!--
<ColumnDefinition Width="Auto"/>
-->
<ColumnDefinition Width="60"/>
</Grid.ColumnDefinitions>
<Button Content="Button" HorizontalAlignment="Left"/>
<Grid Grid.Column="1" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Content="B" Margin="5"/>
<Button Content="Button" Grid.Column="1" Margin="5"/>
</Grid>
</Grid>
produces this output:
In other words, at worst, I'd expect WPF to first calculate the minimum size of the inner grid without considering the star-sizing (e.g. if the short button takes 10 pixels and the long button takes 70, then the total width would be 80), and then still distribute evenly the column widths (i.e. in the 10/70 example, each column would wind up with 40 pixels, truncated the longer button, similar to the above image).
Why should star-sizing sometimes evenly distribute the widths across columns and sometimes not?
Update #2:
Here is a simple example that shows clearly and dramatically how WPF treats star-sizing differently depending on whether it's the one to compute the Grid width or you are:
<Window x:Class="TestGridLayout2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
SizeToContent="WidthAndHeight"
Title="MainWindow">
<Window.Resources>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="1"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="24"/>
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0"/>
<Border Grid.Column="1"/>
<StackPanel>
<TextBlock Text="Some text -- one"/>
<TextBlock Text="Some text -- two"/>
<TextBlock Text="Some text -- three"/>
</StackPanel>
<StackPanel Grid.Column="1">
<TextBlock Text="one"/>
<TextBlock Text="two"/>
<TextBlock Text="three"/>
</StackPanel>
</Grid>
</Window>
When you run the program, you see this:
WPF has ignored star-sizing, setting each column width to its minimum. If you simply click on the window border, as if to resize the window (you don't even have to actually drag the border anywhere), the Grid layout gets redone, and you get this:
At this point, the star-sizing gets applied (as I'd expect) and the columns are proportioned according to the XAML declarations.
I would agree that Ben's answer strongly hints at what might be going on underneath the covers here:
As Ben points out, WPF is ignoring the star-sizing for the purposes of computing the inner Grid object's minimum width (perhaps reasonably…I think there's room for honest debate, but clearly that's one possible and legitimate design).
What's not clear (and which Ben does not answer) is why this should then imply that star-sizing is also ignored when it comes time to calculate the column widths within that inner Grid. Since when a width is imposed externally, proportional widths will cause content to be truncated if necessary to preserve those proportions, why does the same thing not happen when the width is computed automatically based on the minimum required sizes of the content.
I.e. I'm still looking for the answer to my question.
In the meantime, IMHO useful answers include work-arounds to the issue. While not actual answers to my question per se, they are clearly helpful to anyone who may run across the issue. So I'm writing this answer to consolidate all the known work-arounds (for better or worse, one big "feature" of WPF is that there always seems to be at least a few different ways to accomplish the same result :) ).
Workaround #1:
Use UniformGrid instead of Grid for the inner grid object. This object does not have all the same features as Grid and of course doesn't allow for any columns to be of different width. So it may not be useful in all scenarios. But it does easily address the simple one here:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Content="Button" HorizontalAlignment="Left"/>
<UniformGrid Rows="1" Columns="2" Grid.Column="1">
<Button Content="B" Margin="5"/>
<Button Content="Button" Grid.Column="1" Margin="5"/>
</UniformGrid>
</Grid>
Workaround #2:
Bind the MinWidth property of the smaller content object (e.g. here, the first Button in the grid) to the ActualWidth property of the larger one.
This of course requires knowing which object has the largest width. In localization scenarios, that could be problematic, as the XAML would have to be localized in addition to the text resources. But that is sometimes necessary anyway, so… :)
That would look something like this (and is essentially what answerer dub stylee provided as an answer here):
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Content="Button" HorizontalAlignment="Left"/>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Content="B" Margin="5"
MinWidth="{Binding ElementName=button2, Path=ActualWidth}"/>
<Button x:Name="button2" Content="Button" Grid.Column="1" Margin="5"/>
</Grid>
</Grid>
A variation (which for brevity I won't include here) would be to use a MultiBinding that takes all of the relevant controls as input and returns the largest MinWidth of the collection. Of course, then this binding would be used for the Width of each ColumnDefinition, so that all the columns were explicitly set to the largest MinWidth.
There are other variations on the binding scenario as well, depending on which widths you want to use and/or set. None of these are ideal, not just because of the potential localization issues, but also because it embeds more explicit relationships into the XAML. But in many scenarios, it will work perfectly.
Workaround #3:
By using the SharedSizeGroup property of the ColumnDefinition values, it is possible to explicitly force a group of columns to have the same width. In this approach, the inner Grid object's minimum width is then computed on that basis, and of course the widths wind up the same too.
For example:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Content="Button" HorizontalAlignment="Left"/>
<Grid Grid.Column="1" IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="buttonWidthGroup"/>
<ColumnDefinition SharedSizeGroup="buttonWidthGroup"/>
</Grid.ColumnDefinitions>
<Button Content="B" Margin="5"/>
<Button Content="Button" Grid.Column="1" Margin="5"/>
</Grid>
</Grid>
This approach allows one to use Grid, and so get all the normal features of that object, while addressing the specific behavior of concern. I would expect it not to interfere with any other legitimate use of SharedSizeGroup.
However, it does imply "Auto" sizing, and precludes "*" (star) sizing. In this particular scenario, that's not a problem, but as in the case of the UniformGrid work-around, it does limit one's options when trying to combine this with other sizing. E.g. having a third column use "Auto" and wanting the SharedSizeGroup columns to take the remaining space of the Grid.
Still, this would work in many scenarios without any trouble at all.
Workaround #4:
I wound up revisiting this question because I ran into a variation on the theme. In this case, I am dealing with a situation where I want to have different proportions for the columns that are being sized. All of the above workarounds assume equal-sized columns. But I want (for example) one column to have 25% of the space, and another column to have 75% of the space. As before, I want the total size of the Grid to accommodate the minimum width required for all of the columns.
This workaround involves simply explicitly doing myself the computation I feel that WPF ought to be doing. I.e. taking the minimum widths of the content of each column, along with the specified proportional sizes, compute the actual width of the Grid control.
Here is a method that will do that:
private static double ComputeGridSizeForStarWidths(Grid grid)
{
double maxTargetWidth = double.MinValue, otherWidth = 0;
double starTotal = grid.ColumnDefinitions
.Where(d => d.Width.IsStar).Sum(d => d.Width.Value);
foreach (ColumnDefinition definition in grid.ColumnDefinitions)
{
if (!definition.Width.IsStar)
{
otherWidth += definition.ActualWidth;
continue;
}
double targetWidth = definition.ActualWidth / (definition.Width.Value / starTotal);
if (maxTargetWidth < targetWidth)
{
maxTargetWidth = targetWidth;
}
}
return otherWidth + maxTargetWidth;
}
This code finds the smallest width that can still accommodate every star-sized column at that columns minimum width and proportional sizing, along with the remaining columns that are not using star-sizing.
You can call this method at an appropriate time (e.g. in the Grid.Loaded event handler), and then assign its return value to the Grid.Width property to force the width to the right size to accommodate the minimum required widths for all columns while maintain the specified proportions.
A similar method would do the same thing for row heights.
Workaround #5:
I guess it bears pointing out: one can simply specify the Grid size explicitly. This only works for content where the size is known in advance, but again, in many scenarios this would be fine. (In other scenarios, it will truncate content, because even if the size specified is too small, when it's explicit, WPF goes ahead and applies the star-sizing proportions).
I encourage others to add additional work-arounds to this answer, if they are aware of good work-arounds that are materially different from those already shown. Alternatively, feel free to post another answer with your work-around, and I will (at my earliest convenience :) ) add it here myself.
This is a bit of a workaround and doesn't explain the cause of the behavior you are describing, but it achieves what you are looking for:
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button HorizontalAlignment="Left" Content="Button" />
<Grid Grid.Column="1"
ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Margin="5"
MinWidth="{Binding ElementName=Button2, Path=ActualWidth}"
Content="B"
x:Name="Button1" />
<Button Grid.Column="1"
Margin="5"
Content="Button"
x:Name="Button2" />
</Grid>
</Grid>
I have to assume that an Auto column width is calculated based on the minimum width of the child controls. I wasn't able to confirm or disprove this looking through any documentation, but it is probably expected behavior. In order to force the Button controls to take up equal size, you can just bind the MinWidth property to the ActualWidth of the other Button. In this example, I only bound the Button1.MinWidth to the Button2.ActualWidth to illustrate your desired behavior.
Also, please ignore the Button.Height, I didn't bother to set them different than the default.
From the documentation (Modern apps) (WPF):
starSizing
A convention by which you can size rows or columns to take the remaining available space in a Grid.
It doesn't cause more minimum space to be requested, it affects distribution of space in excess of the minimum.
Related
I have the following XAML
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Hello World" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Hello ABC DEF World" TextTrimming="CharacterEllipsis" />
</Grid>
</Window>
This results in the following User Interface:
I would like the TextBlock "Hello ABC DEF World" to trim and not extend the column width.
To have this result:
Edit:
Want to point out
I wouldn't need it to be a Grid it could be any content control (StackPanel, DockPanl, Canvas and so on)
I wouldn't need it to be a TextBlock it could be any control (Run, Label and so on)
If what I desire is possible with a different combination of controls, I am more than willing to give it a try.
What I want in non-code terms:
I want 2 lines of text, the first line of text is the "main" information, and the second line of text is the "minor" information.
The "main" information should stretch fully to show its full text.
The "minor" information should only stretch as far as the main goes and not more, if it is longer it should Trim
I know I could achieve this goal with the following XAML:
<TextBlock ...
x:Name="MainInfo" />
<TextBlock ...
MaxWidth="{Binding Mode=OneWay, Path=ActualWidth, ElementName=MainInfo}" />
But if possible I would like to avoid the Binding on ActualWidth.
I hoped that HorizontalAlignment = Left; would prevent the TextBlock's desire to stretch, but that wasn't the case.
But if possible I would like to not use the Binding on ActualWidth.
Well, you need to define the width contraint somehow. Auto effectively means that the column will grow along with the widest element in it, i.e. the "minor" information TextBlock in this case.
So you should set the Width of the column to the ActualWidth of MainInfo, for example using a binding. Or programmatically. Either way, you have to set it one way or another.
You could achieve this in multiple ways.
Depends on the exact desired purpose.
One notable and easy example would be to use some trickery
You could put the main textblock and a rectangle in a horizontally aligned stackpanel with a row span of 2 and with a higher Z index than the secondary textblock. You set the rectangle to have the height equal with the sum of the two textblocks and the width must be set by you after your desired specifications. The two textblocks must have set a fixed height, and the textblock that is inside the stackpanel with the rectangle must be aligned to the top vertically inside the stackpanel. The result, if implemented correctly, should be a rectangle that is covering the part of the secondary textblock that is making the secondary textblock bigger than the main textblock.
I want to achieve the following in XAML (WPF):
By default, maintain a 60%-40% split for a grid with 2 horizontal elements
If the second element is blank (or smaller than 40%), allow the first element to take up the remaining space if it needs it
If the first element is blank (or smaller than 60%), allow the second element to take up the remaining space if it needs it
This feels like a "preferred width" instead of a "MaxWidth" type thing. Additionally, the first element is left aligned and the second element is right aligned.
Some things I've tried that don't work (also couldn't find if this question was answered - searches didn't result in what I wanted)
This doesn't work because it sets both to columns to a specified width:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6*"></ColumnDefinition>
<ColumnDefinition Width="4*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="Test1"/>
<TextBlock Grid.Column="1"
Text="Test2" />
</Grid>
This doesn't work because although if both take up 100% of their spaces, it looks fine, but auto won't allow one element to overflow into the other area if a "MaxWidth" is set - I would like "MaxWidth" to almost be like a "PreferredWidth":
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"
MaxWidth="60% of the pixels"/>
<ColumnDefinition Width="Auto"
MaxWidth="40% of the pixels" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="Test1"/>
<TextBlock Grid.Column="1"
TextAlignment="Right"
Text="Test2" />
</Grid>
Is there a way to achieve (what seems like a relatively easy product spec) through just XAML? And if not, what are the alternatives?
The code below does a row-column demonstration of 3 rows where the last row had 3 columns. in each, the second element is a grid splitter.
if splitter's alignment is set to "center", it works as expected to resize others. but if it is set to left/right for horizontal (or top/bottom for vertical) it just shrinks other two while extending its cell (no less than its size)
Can someone explain why does the GridSplitter behave like this? the code is simple WPF code and can be copy-pasted to C# or VB WPF application's main xaml.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="25"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" Background="Lime">
<Label Content="Label" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</DockPanel>
<GridSplitter Grid.Row="1" Height="5" Background="#FF7F7F7F" VerticalAlignment="Center" HorizontalAlignment="Stretch" ResizeDirection="Rows"/>
<DockPanel Grid.Row="2">
<Grid DockPanel.Dock="Top" Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DockPanel Grid.Column="0" Background="Red">
<Label Content="Label" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</DockPanel>
<GridSplitter Grid.Column="1" Width="5" Background="#FF7F7F7F" VerticalAlignment="Stretch" HorizontalAlignment="Center" ResizeDirection="Columns"/>
<DockPanel Grid.Column="2" Background="Blue">
<Label Content="Label" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</DockPanel>
</Grid>
</DockPanel>
</Grid>
GridSplitter has a property called ResizeBehavior which defines the action the question described. If not set manually the default behavior is BasedOnAlignment, meaning it is based on the HorizontalAlignment and VerticalAlignment values you are setting.
If they are set as in the code, ResizeBehavior is defaulted to PreviousAndNext. This will cause it to redistribute space on either side of the GridSplitter.
GridSplitter parts in the code are equivalent to these manual settings of ResizeBehavior.
...
<GridSplitter ResizeBehavior="PreviousAndNext" Grid.Row="1" Height="5" Background="#FF7F7F7F" VerticalAlignment="Top" HorizontalAlignment="Stretch" ResizeDirection="Rows"/>
...
<GridSplitter ResizeBehavior="PreviousAndNext" Grid.Column="1" Width="5" Background="#FF7F7F7F" VerticalAlignment="Stretch" HorizontalAlignment="Left" ResizeDirection="Columns"/>
...
Update with more explanation about default ResizeBehavior of BasedOnAlignment:
At the end of this answer below is a link to an image of a table excerpted from the book WPF 4.5 Unleashed By Adam Nathan (I do not yet have enough reputation to place this image directly here and so am only allowed to create it as a link).
The table shows what the GridSplitter will look like (shown as the colored rectangles/squares) depending upon the HorizontalAlignment and VerticalAlignment settings it is given. If neither of those settings have a stretch, then the GridSplitter will end up as a small dot and so it is only the cases where one of the alignments is set to stretch that we are interested in (as you did in your code).
When the rows or columns are proportionally sized (as is in your case with using asterisks), then dragging the GridSplitter changes the coefficients for the two cells indicated in the table accordingly.
As you can see when the one alignment is set to stretch and the other to center, the two cells affected are the ones that are on either side of the GridSplitter. Thus you see the behavior you first report of those cells on either side being sized equally.
But when set to the Left/Right or Top/Bottom values (depending upon if you are working with vertical or horizontal GridSplitters) then, as you can see from the table, the GridSplitter itself becomes one of the two affected cells. So if, for example, it is a vertical GridSplitter and you set the HorizontalAlignment to Left, you will only be able to move the GridSplitter from where it starts in the center towards the left and that will size that left cell smaller and make the GridSplitter itself larger (and in the process take away space from the right cell). You cannot, however, move the GridSplitter to the right and make the right cell smaller.
Table: Cells Directly Affected When Dragging a GridSplitter with Various Alignment Settings
I'm trying to use HorizontalAlignment="Left" in the following situation:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Grid HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Background="Gray" Text="Small Text" TextWrapping="Wrap"/>
<TextBlock Grid.Column="1" Background="White" Text="This is a very large amount of text" TextWrapping="Wrap"/>
<TextBlock Grid.Column="2" Background="Gray" Text="Medium amount of text" TextWrapping="Wrap"/>
</Grid>
</Window>
My goal is to be able to resize the window, and have the three TextBlocks resize themselves proportionally. This works, but the grid is putting some blank space to the right of the final column, and as I try to resize towards the final column, the columns start to shrink. I want this shrinking behavior, but I don't want it to start until there is no more white space to the right of the rightmost column.
I can't use a UniformGrid as the text lengths can vary, and no other built-in WPF control that I've seen has the ability to resize all children when the parent size changes. I've looked into creating a custom panel, but that seems to be more trouble than it's worth. I feel like something much more simple can be done here.
Any suggestions or ideas are appreciated.
You'll have to build your own custom panel, and handle the case where the AvailableWidth is less then the panel's children DesiredWidth
Panel layout in WPF (Grid is a Panel) is a 2 step process, in the first pass the Panel iterates over its children and provides them with the panel's AvailableWidth. The children respond to this by computing their DesiredWidth.
In the second pass the Panel arranges the children according to their DesiredWidth. In this second pass you have access to the width that all the children (in your case, TextBlocks) require. If it is less than the panel's available width you can compute a percentage to give each one so that they appear to shrink uniformly.
Here's a resource that shows how you can create your own custom panel
What about this?
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
I have a page like this:
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
here are contents
they are forever absolutely in the center of the screen
no matter of the resolution/size
</StackPanel>
</Grid>
Everything is working fine. But now I want to add a back button in the top-left corner.
And I don't want to split the grid into 2 columns and 2 rows like this:
the contents are no longer absolutely centered, even we can split the grid by percent, because the contents are sometimes very wide and sometimes very narrow.
I want to know how can I keep the contents horizontal/vertical aligned "Center", and then set the back button's position relatively to the content.
I would suggest using a grid layout with 3 columns to ensure the content is centered with the columns widths set to *,Auto, *. This will ensure the main content is always centered and not care about the size of the button. You can then use margins to set the seperation as required. This is a techinique I have used in SL, WPF & Metro.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button HorizontalAlignment="Right" VerticalAlignment="Top" Content="Do Something"/>
<ContentControl VerticalAlignment="Top" Content="My custom content"/>
</Grid>
slightly hacky ansewer
You might be able to achieve by positioning your stackpanel in the center, and then set a negative left margin the width of the button to shift everything left by the required amount...
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Margin="-45,0,0,0">
<button with width and padding totalling 45px />
here are contents
they are forever absolutely in the center of the screen
no matter of the resolution/size
</StackPanel>
</Grid>