views:

47

answers:

3
+1  Q: 

WPF. Layout issue.

Hello, guys I have StackPanel. I need place there TextBlock with TextAlignment = TextAlignment.Center[Center of stackPanel] and button at right side with small margin. How can I achieve such layout with wpf.

How can I add button to StackPanel, that my TextBlock doesn't move from center.

A: 

How about something like:

<StackPanel>
    <Grid HorizontalAlignment="Stretch">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <TextBlock Text="MyTextBlock" TextAlignment="Center"/>
        <Button HorizontalAlignment="Right" Grid.Column="1">MyButton</Button>
    </Grid>
</StackPanel>

EDIT:

If you want the textblock to be in the center of the grid, you can just remove the ColumnDefinitions above. However, note that if the Grid becomes small enough here, the button will overlap with the TextBlock.

<StackPanel>
        <Grid HorizontalAlignment="Stretch">
            <TextBlock Text="MyTextBlock" TextAlignment="Center"/>
            <Button HorizontalAlignment="Right">MyButton</Button>
        </Grid>
    </StackPanel>
karmicpuppet
see EDIT. check out if that works enough for you.
karmicpuppet
Thanks, but if I want more complex variant layout of this grid? This variant without columns isn't very flexible. If I want two or three buttons at right side. I think absolut margins isn't nice way.
Andrew Kalashnikov
@karmicpuppet: if you are using a Grid, why use the StackPanel at all?
Wonko the Sane
@Wonko: I was under the impression that his outer panel is a stackpanel and he wants each "row" of the StackPanel to have a TextBlock and a Button (for which I used a Grid).
karmicpuppet
Ah, I see. So this is one of n Grids.
Wonko the Sane
+2  A: 

Try something like this:

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <TextBox x:Name="txtCentered"
                 Grid.Column="0"
                 Grid.ColumnSpan="2"
                 HorizontalAlignment="Center"
                 VerticalAlignment="Center"
                 Text="Here Is My Text Box" />

        <StackPanel x:Name="stackButtons"
                    Grid.Column="1"
                    Orientation="Vertical"
                    VerticalAlignment="Center">
            <Button x:Name="btnOne" Content="Button One" />
            <Button x:Name="btnTwo" Content="Button Two" />
            <Button x:Name="btnThree" Content="Button Three" />
       </StackPanel>
</Grid>

Notice that the TextBox spans the entire Grid (ColumnSpan="2"), so that it will be absolutely centered in the Grid (HorizontalAlignment="Center"). The second column will just have a StackPanel (or Grid, or UniformGrid, or...) with the buttons.

NOTE: The known drawback of this design is that the buttons could overlap the TextBox if the TextBox is big enough and the Grid is small enough. Care will have to be taken to avoid this, and is left as an exercise for the developer. However, this drawback will occur on any implementation where the requirement is that the TextBox is dead-center of the layout.

Wonko the Sane
Obviously, if you want to use TextBlock instead of TextBox, you can. Your question and comments mention both, and I read "TextBox" last. :)
Wonko the Sane
Grid.ColumnSpan="2"was key feature that i Forget. Thanks a lot!!!
Andrew Kalashnikov
A: 

To avoid potential overlap between the TextBlock and Button, you can calculate the left margin for the Button that ends up next to the TextBlock in the center using a Value Converter. That said I still like answer provided by @Wonko as it is simple and standard.

Here is the XAML:

<Window x:Class="TextBoxInCenter.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:TextBoxInCenter" 
    Title="MainWindow" 
    Height="350" Width="525">
  <Grid>
    <Grid.Resources>
        <local:CustomThicknessValueConverter x:Key="CustomThicknessValueConverter" />
    </Grid.Resources>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <TextBlock 
        x:Name="CenterTextBox"
        Grid.Column="0" 
        Grid.ColumnSpan="2"
        Grid.Row="0"
        Text="Text in Center" 
        HorizontalAlignment="Center" 
        VerticalAlignment="Center"
        TextAlignment="Center"/>
    <StackPanel
        Grid.Column="1"
        Grid.Row="0"
        Orientation="Horizontal">
        <Button 
            Margin="{Binding ElementName=CenterTextBox, 
                       Path=ActualWidth, 
                       Converter={StaticResource CustomThicknessValueConverter}}"
            Height="23"
            Content="Click me 1">
        </Button>
        <Button 
            Height="23"
            Content="Click me 2">
        </Button>
    </StackPanel>
  </Grid>
</Window>

Here is the Value Converter:

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Data;

namespace TextBoxInCenter
{
  public class CustomThicknessValueConverter : IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      Debug.WriteLine("Convert");

      Thickness thickness = new Thickness(0, 0, 0, 0);

      if ( value != null )
      {
         double actaulwidth = (double)value;
         thickness.Left = actaulwidth/2;
      }

      return thickness;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      throw new NotImplementedException();
    }
  }
}
Zamboni