HorizontalAlignment = Stretch, MaxWidth i Left wyrównane w tym samym czasie?

96

Wydaje się, że to powinno być łatwe, ale jestem zaskoczony. W WPF chciałbym TextBox, który rozciąga się do szerokości jego elementu nadrzędnego, ale tylko do maksymalnej szerokości. Problem polega na tym, że chcę, aby został on uzasadniony w swoim rodzicu. Aby go rozciągnąć, musisz użyć HorizontalAlignment = "Stretch", ale wtedy wynik jest wyśrodkowany. Eksperymentowałem z HorizontalContentAlignment, ale wydaje się, że nic nie daje.

Jak sprawić, aby to niebieskie pole tekstowe rosło wraz z rozmiarem okna, miało maksymalną szerokość 200 pikseli i było wyrównane do lewej strony?

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <StackPanel>  
    <TextBox Background="Azure" Text="Hello" HorizontalAlignment="Stretch" MaxWidth="200" />
  </StackPanel>
</Page>

Co to za sztuczka?

Scott Bussinger
źródło

Odpowiedzi:

89

Można ustawić HorizontalAlignmentdo lewej, ustaw MaxWidth, a następnie wiążą Widthsię do ActualWidthelementu nadrzędnego:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <StackPanel Name="Container">   
    <TextBox Background="Azure" 
    Width="{Binding ElementName=Container,Path=ActualWidth}"
    Text="Hello" HorizontalAlignment="Left" MaxWidth="200" />
  </StackPanel>
</Page>
Nir
źródło
7
Nie zmienia rozmiaru… Wydaje się pasować do treści… czy czegoś mi brakuje?
Gishu
Wygląda na to, że powoduje awarię mojego odtwarzacza
Silverlight
2
@Gishu, upewnij się ustawić HorizontalAlignment="Stretch"na Container elemencie. (ps, zdaję sobie sprawę, że zadałeś to pytanie ponad 6 lat temu.)
David Murdoch
51
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" MaxWidth="200"/>
    </Grid.ColumnDefinitions>

    <TextBox Background="Azure" Text="Hello" />
</Grid>
Kent Boogaart
źródło
Myślę, że musisz ustawić VerticalAlignment = "Top" dla pola tekstowego .. wydaje się być domyślnie rozciągnięte.
Gishu
1
+1. Ładnie i czysto. Za każdym razem, gdy próbuję zarządzać układem, wiążąc się z jakąś rzeczywistą szerokością (jak w zaakceptowanej odpowiedzi), robi się bałagan.
Eren Ersönmez
1
Właśnie natknąłem się na to pytanie, próbując rozwiązać ten sam problem. W moim przypadku jest to najlepsza odpowiedź, ponieważ działa w WinRT. Druga odpowiedź nie, ponieważ nie możesz powiązać ActualWidth w WinRT.
Slade
Slade - właśnie to zrobiłem w aplikacji ze Sklepu Windows: MaxWidth = "{Binding ActualWidth, ElementName = Layout}" i działało dobrze przy powiązaniu MaxWidth z inną właściwością ActualWidth elementów. Nie jestem pewien, dlaczego to zadziałało, ale zrobiło to, czego się spodziewałem, i jak wspomniano wcześniej w odpowiedzi, która miała rozwiązanie wiążące szerokość, nie zmieniło rozmiaru elementu, gdy rozmiar elementu nadrzędnego zmienił się z powodu powiększenia okna lub mniejszy.
David Rector
8

Obie udzielone odpowiedzi zadziałały w przypadku problemu, który stwierdziłem - dzięki!

Jednak w mojej prawdziwej aplikacji próbowałem ograniczyć panel wewnątrz ScrollViewer, a metoda Kenta nie radziła sobie z tym zbyt dobrze z jakiegoś powodu, którego nie szukałem. Zasadniczo sterowanie mogłoby rozszerzyć się poza ustawienie MaxWidth i pokonać mój zamiar.

Technika Nira działała dobrze i nie miała problemu z ScrollViewer, chociaż jest jedna drobna rzecz, na którą należy uważać. Chcesz mieć pewność, że prawy i lewy margines na TextBox są ustawione na 0 lub będą przeszkadzać. Zmieniłem również powiązanie, aby używać ViewportWidth zamiast ActualWidth, aby uniknąć problemów, gdy pojawił się pionowy pasek przewijania.

Scott Bussinger
źródło
6

Możesz użyć tego dla szerokości swojego DataTemplate:

Width="{Binding ActualWidth,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ScrollContentPresenter}}}"

Upewnij się, że katalog główny DataTemplate ma Margin = "0" (możesz użyć jakiegoś panelu jako root i ustawić Margin na elementy podrzędne tego katalogu)

Filip Skakun
źródło
1

Funkcjonalnie podobny do zaakceptowanej odpowiedzi, ale nie wymaga określenia elementu nadrzędnego:

<TextBox
    Width="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type FrameworkElement}}}"
    MaxWidth="500"
    HorizontalAlignment="Left" />
maxp
źródło
1

Może nadal mogę pomóc komuś, kto wpadnie na to pytanie, ponieważ jest to bardzo stary problem.

Ja też tego potrzebowałem i napisałem zachowanie, aby się tym zająć. Oto zachowanie:

public class StretchMaxWidthBehavior : Behavior<FrameworkElement>
{        
    protected override void OnAttached()
    {
        base.OnAttached();
        ((FrameworkElement)this.AssociatedObject.Parent).SizeChanged += this.OnSizeChanged;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        ((FrameworkElement)this.AssociatedObject.Parent).SizeChanged -= this.OnSizeChanged;
    }

    private void OnSizeChanged(object sender, SizeChangedEventArgs e)
    {
        this.SetAlignments();
    }

    private void SetAlignments()
    {
        var slot = LayoutInformation.GetLayoutSlot(this.AssociatedObject);
        var newWidth = slot.Width;
        var newHeight = slot.Height;

        if (!double.IsInfinity(this.AssociatedObject.MaxWidth))
        {
            if (this.AssociatedObject.MaxWidth < newWidth)
            {
                this.AssociatedObject.HorizontalAlignment = HorizontalAlignment.Left;
                this.AssociatedObject.Width = this.AssociatedObject.MaxWidth;
            }
            else
            {
                this.AssociatedObject.HorizontalAlignment = HorizontalAlignment.Stretch;
                this.AssociatedObject.Width = double.NaN;
            }
        }

        if (!double.IsInfinity(this.AssociatedObject.MaxHeight))
        {
            if (this.AssociatedObject.MaxHeight < newHeight)
            {
                this.AssociatedObject.VerticalAlignment = VerticalAlignment.Top;
                this.AssociatedObject.Height = this.AssociatedObject.MaxHeight;
            }
            else
            {
                this.AssociatedObject.VerticalAlignment = VerticalAlignment.Stretch;
                this.AssociatedObject.Height = double.NaN;
            }
        }
    }
}

Następnie możesz go użyć w następujący sposób:

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

    <TextBlock Grid.Column="0" Text="Label" />
    <TextBox Grid.Column="1" MaxWidth="600">
          <i:Interaction.Behaviors>                       
               <cbh:StretchMaxWidthBehavior/>
          </i:Interaction.Behaviors>
    </TextBox>
</Grid>

I na koniec zapomnieć o użyciu System.Windows.Interactivityprzestrzeni nazw do użycia zachowania.

YC
źródło
0

użyłbym SharedSizeGroup

<Grid>
    <Grid.ColumnDefinition>
        <ColumnDefinition SharedSizeGroup="col1"></ColumnDefinition>  
        <ColumnDefinition SharedSizeGroup="col2"></ColumnDefinition>
    </Grid.ColumnDefinition>
    <TextBox Background="Azure" Text="Hello" Grid.Column="1" MaxWidth="200" />
</Grid>
Patrick Cairns
źródło
0

W moim przypadku musiałem umieścić pole tekstowe w panelu stosu, aby rozciągnąć pole tekstowe po lewej stronie. Dziękuję za poprzedni post. Na przykład ustawiłem kolor tła, aby zobaczyć, co się dzieje, gdy zmienia się rozmiar okna.

<StackPanel Name="JustContainer" VerticalAlignment="Center" HorizontalAlignment="Stretch" Background="BlueViolet" >
    <TextBox 
       Name="Input" Text="Hello World" 
       MaxWidth="300"
       HorizontalAlignment="Right"
       Width="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type FrameworkElement}}}">
    </TextBox>
</StackPanel>
sparedev
źródło