Laden...

[gelöst] Button in StackPanel "festhalten" wenn content darüber wächst

Erstellt von ByteDevil vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.350 Views
ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren
[gelöst] Button in StackPanel "festhalten" wenn content darüber wächst

Hallo,

hat jemand eine Idee wie ich das schaffen könnte? Also ich habe eine vertikales Stackpanel mit mehreren Expandern darin. Dieses StackPanel steckt in einem ScrollViewer. Unterhalb dessen ist ein Button den der User auf jeden Fall braucht.
Brauchen die Expander nun mehr Platz als da ist, erscheint eine vertikale Scrollbar. Der Button bleibt auch sichtbar. Nun ist mein Problem, dass der Button IMMER ganz unten ist...also auch wenn mehr als genug Platz da ist. Ich hätte ihn aber immer gern direkt unter den Expandern...

Hier mal ein Minimalbeispiel:


<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <ScrollViewer Grid.Row="0">
        <StackPanel>
            <Expander>
                <Rectangle Width="100" Height="200"/>
            </Expander>
            <Expander>
                <Rectangle Width="100" Height="200"/>
            </Expander>
            <Expander>
                <Rectangle Width="100" Height="200"/>
            </Expander>
        </StackPanel>
    </ScrollViewer>
    <Button Content="Button der immer sichtbar sein soll" Grid.Row="1" VerticalAlignment="Top"/>
</Grid>

U
69 Beiträge seit 2019
vor 4 Jahren

Ich würde mal darauf tippen, dass der Button ein VerticalAlignment braucht.

“Knowledge cannot replace friendship. I'd rather be an idiot than lose you.”

  • Patrick to Spongebob
ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Ich würde mal darauf tippen, dass der Button ein
>
braucht.

Aber er ist alleine in einer Auto-Size GridRow? Oder wie meinst du das?

656 Beiträge seit 2008
vor 4 Jahren

Naja, das Problem ist eher, dass die RowDefinition deines StackPanel keine Height angegeben hat. Standardmäßig ist die \*, drum nimmt das Ding den ganzen Platz ein, den der Button nicht braucht.
Damit wird der Button auch immer unten dran kleben.

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Naja, das Problem ist eher, dass die RowDefinition deines StackPanel keine Height angegeben hat. Standardmäßig ist die \*, drum nimmt das Ding den ganzen Platz ein, den der Button nicht braucht.
Damit wird der Button auch immer unten dran kleben.

Richtig, eine feste Höhe kann ich aber nicht definieren, weil ich das Fenster ja größer oder kleiner machen können möchte. Auf Auto kann ich es auch nicht setzen, weil sonst der Button im nirgendwo verschwindet und das Grid einfach immer größer wird.

Edit: Es muss auch nicht zwingend diese Konstruktion mit dem StackPanel/Grid sein. Suche nur etwas das funktioniert^^

656 Beiträge seit 2008
vor 4 Jahren

Jo, ich kenn das Problem leider nur zu gut von unseren eigenen Views - und dort konnten wir meistens durch umsortieren der Controls ein brauchbares UI erreichen.
Gibts einen Grund, warum der Button unten sein muss? Sonst würd ich den einfach mal nach oben verfrachten.

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Jo, ich kenn das Problem leider nur zu gut von unseren eigenen Views - und dort konnten wir meistens durch umsortieren der Controls ein brauchbares UI erreichen.
Gibts einen Grund, warum der Button unten sein muss? Sonst würd ich den einfach mal nach oben verfrachten.

Leider ist das keine Option 😦 Handelt sich um eine Filter-UI wo ein Suchbutton unten sein soll. Würde eher verwirren wenn der Button über den ganzen Filtern ist.

1.040 Beiträge seit 2007
vor 4 Jahren

Evtl. hilft dir die Angabe von Height="Auto" und einer Angabe bei MaxHeight.

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Evtl. hilft dir die Angabe von Height="Auto" und einer Angabe bei MaxHeight.

Aber was sollte ich sinnvolles bei MaxHeight angeben?

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Habe mir jetzt selbst ein UserControl geschrieben das macht was ich möchte. Hier ist es, falls ich jemandem damit eine Freude machen kann:


public class TrailerPanel : UserControl
{
    readonly Grid mainGrid = new Grid();
    readonly ScrollViewer scrollViewer = new ScrollViewer();

    public FrameworkElement MainControl
    {
        get { return (FrameworkElement)GetValue(MainControlProperty); }
        set { SetValue(MainControlProperty, value); }
    }
    public static readonly DependencyProperty MainControlProperty =
        DependencyProperty.Register("MainControl", typeof(FrameworkElement), typeof(TrailerPanel), new PropertyMetadata(null, MainControl_PropertyChanged));
    private static void MainControl_PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) => (obj as TrailerPanel).scrollViewer.Content = (obj as TrailerPanel).MainControl;

    public FrameworkElement TrailingControl
    {
        get { return (FrameworkElement)GetValue(TrailingControlProperty); }
        set
        {
            if (TrailingControl != null)
                mainGrid.Children.Remove(TrailingControl);
            SetValue(TrailingControlProperty, value);
        }
    }
    public static readonly DependencyProperty TrailingControlProperty =
        DependencyProperty.Register("TrailingControl", typeof(FrameworkElement), typeof(TrailerPanel), new PropertyMetadata(null, TrailingControl_PropertyChanged));
    private static void TrailingControl_PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        (obj as TrailerPanel).mainGrid.Children.Add((obj as TrailerPanel).TrailingControl);
        Grid.SetRow((obj as TrailerPanel).TrailingControl, 1);
    }

    protected override void OnInitialized(EventArgs e)
    {
        base.OnInitialized(e);

        Content = mainGrid;

        mainGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
        mainGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
            
        mainGrid.Children.Add(scrollViewer);
        Grid.SetRow(scrollViewer, 0);

        SizeChanged += BetterTrailerPanel_SizeChanged;
    }

    private void BetterTrailerPanel_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        mainGrid.RowDefinitions[0].MaxHeight = ActualHeight - mainGrid.RowDefinitions[1].ActualHeight;
        scrollViewer.MaxHeight = ActualHeight - mainGrid.RowDefinitions[1].ActualHeight;
    }
}

Verwendung:


<Grid>
    <controls:TrailerPanel>
        <controls:TrailerPanel.MainControl>
            <StackPanel>
                <Expander>
                    <Rectangle Width="100" Height="200"/>
                </Expander>
                <Expander>
                    <Rectangle Width="100" Height="200"/>
                </Expander>
                <Expander>
                    <Rectangle Width="100" Height="200"/>
                </Expander>
            </StackPanel>
        </controls:TrailerPanel.MainControl>
        <controls:TrailerPanel.TrailingControl>
            <Button Content="Button der immer sichtbar sein soll" Grid.Row="1" VerticalAlignment="Top"/>
        </controls:TrailerPanel.TrailingControl>
    </controls:TrailerPanel>
</Grid>