XAML How to arrange an element after a centered one - c#

I want to create a button that will display some text together with a status icon inside. The text should be centered and the status icon should go right next to the text. Something like this:
I didn't find a way how to center only the text and then positioning the icon after the centered text. Right now I am using a Grid solution which centers the text and aligns the icon to the right.
<Button VerticalContentAligment="Stretch" HorizontalContentAligment="Stretch">
<Grid>
<TextBlock VerticalAligment="Center" HorizontalAligment="Center"/>
<Image VerticalAligment="Center" HorizontalAligment="Right"/>
</Grid>
</Button>
It's not what I want but it's working for the button's size I have at the moment.
I know that this can be accomplished using some binding magic but it seems too simple for this. It will be great if you can point me to a solution without binding magic but I will grateful even for one with it.

A Grid with 3 columns should work. When the left and right columns have equal width, the middle one is automatically centered.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1" VerticalAlignment="Center"/>
<Image Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Left"/>
</Grid>

Related

GridSplitter weird behavior, or is it not?

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

WPF Create Sidebar Navigation

I am curious about how to create a sidebar navigation something like:
I tried using an uniform grid but there ended up being too much spacing between "buttons" and I'm not sure if it's possible to modify the tab control to act like full width buttons instead of overhead tabs.
Also if if its possible to add icons that would be a huge plus.
You can make a Gridcolumn in your Standard grid with your wished Width. The into this Column you can put a stackpanel which fills your buttons from top to bottom.
Like That:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<Button Height="40">Test</Button>
<Button Height="40">Test2</Button>
</StackPanel>
</Grid>
It would look like this:
If i missunderstod you please tell me and im gona edit it.
To add Images you can then create another grid in your Button with two columns: Like this:
<Button>
<Grid Height="40" Width="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="pack://siteoforigin:,,,/Resources/dll.png"></Image>
<TextBlock Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center">Text</TextBlock>
</Grid>
</Button>
Note that you have to set your grid to Width="200" like you set your main Grid.Column because the Grid would not be the whole width of the button if you would not set it too 200.
Then the List would look like this:

Left HorizontalAlignment on a Grid

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>

WPF clickable area around controls in grid

I have an issue with making a custom title bar for a form. It would contain a search textbox aswell as a few sliders, as seen on this image:
Now, imagine that as the title bar - everything that is not a part of the controls themselves (the textbox which is surrounded by a border element, and the slider) needs to be mousedownable for dragging purposes.
I've tried this:
<Grid MouseDown="TitleGridMouseDown">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="135"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<Slider Grid.Column="1" Margin="5 15 5 0" Width="100" MouseDown="TitleGridMouseDown"/>
<Slider Grid.Column="2" Margin="5 15 5 0"/>
<Border Grid.Column="3" CornerRadius="10" BorderThickness="1" BorderBrush="White" Width="180" Height="20" Background="White">
<TextBox Background="Transparent" BorderThickness="0" Height="20"/>
</Border>
</Grid>
However it's of no avail. There's a small part between the two sliders, like a few pixel area, which actually works (DragMove(); in the event itself). I don't have an awful lot of experience this type of things in WPF, but it feels to me like the area shrinks to the control. For instance, nothing changes if I place the border object into a button and try to bind the event to the button.
How should I approach this?
Your problem here is that you want to capture the MouseDown event on the grid element. Since your grid has no Background set, its defaulted to null. The MouseDown event does not get raised. Think of it like it is going through the grid without actually hitting it. A Background=Transparent on your top grid should solve the problem.

How to set a control's position according to another in windows 8 app?

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>

Categories