Laden...

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

Letzter Beitrag vor 4 Jahren 10 Posts 1.374 Views
[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>

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

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?

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.

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^^

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.

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.

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

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

Aber was sollte ich sinnvolles bei MaxHeight angeben?

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>