Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically resizing an open Accordion

I have an Accordion and the height of its content can be dynamically resized. I would like to see the Accordion dynamically respond to the child item's height, but I'm having trouble doing this.

    <lt:Accordion Name="MyAccordion"
                  SelectionMode="ZeroOrOne"
                  HorizontalAlignment="Stretch">
        <lt:AccordionItem Name="MyAccordionItem"
                          Header="MyAccordion"
                          IsSelected="True"
                          HorizontalContentAlignment="Stretch"
                          VerticalAlignment="Stretch">
            <StackPanel>
                <Button Content="Grow" Click="Grow"/>
                <Button Content="Shrink" Click="Shrink"/>
                <TextBox Name="GrowTextBox"
                         Text="GrowTextBox"
                         Height="400"
                         Background="Green"
                         SizeChanged="GrowTextBox_SizeChanged"/>
            </StackPanel>
        </lt:AccordionItem>
    </lt:Accordion>


    private void Grow(object sender, System.Windows.RoutedEventArgs e)
    {
        GrowTextBox.Height += 100;
    }

    private void Shrink(object sender, System.Windows.RoutedEventArgs e)
    {
        GrowTextBox.Height -= 100;
    }

    private void GrowTextBox_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
    {
        MyAccordion.UpdateLayout();
        MyAccordionItem.UpdateLayout();
    }

Mind you, if I collapse and then re-open the accordion, it takes shape just the way I want, but I'd like this resizing to occur immediately when the child resizes.

I feebly attempted to fix this by adding a SizeChanged event handler that calls UpdateLayout() on the Accordion and AccordionItem, but this doesn't have any visual effect. I can't figure out where proper resizing takes place inside the Accordion control. Does anyone have an idea?

like image 430
Andrew Lavers Avatar asked May 12 '10 22:05

Andrew Lavers


3 Answers

Try this one

 //here i am creating a size object depending on child items height and width
        // and 25 for accordian item header...
        // if it works you can easily update the following code to avoid exceptional behaviour
        Size size = new Size();
        size.Width = GrowTextBox.ActualWidth;
        size.Height = grow.ActualHeight + shrink.ActualHeight + GrowTextBox.ActualHeight + 25;
        MyAccordion.Arrange(new Rect(size));

In the above code i am just rearranging accordion depending on child item size.

like image 155
Bathineni Avatar answered Nov 09 '22 08:11

Bathineni


I have a similar problem, my simple hack is as follows:

private void GrowTextBox_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
{
        MyAccordionItem.Measure(new Size());
        MyAccordionItem.UpdateLayout();
}

Hope it works for you too..

Cheers

like image 32
Joshscorp Avatar answered Nov 09 '22 09:11

Joshscorp


I had a slightly different problem - resizing my window sometimes didn't correctly adjust the Accordion item size, so the header of the next item would be stuck below the window or in the middle of it.

I solved this by creating a timer that is started in SizeChanged, and that deselects and immediately reselects the current item, after which the layout seems to be readjusted and turns up correct. Might help you as well. You could dispense with the timer, I introduced it to prevent continuous calls when the user drag resizes the window, it also gives a kind of feathery effect because of the delay.

public partial class MyAccordion : System.Windows.Controls.Accordion
{
    private Timer _layoutUpdateTimer = new Timer(100);

    public MyAccordion
    {
        this.SizeChanged += (s, e) =>
        {
            _layoutUpdateTimer.Stop(); // prevents continuous calls
            _layoutUpdateTimer.Start();
        };
        _layoutUpdateTimer.Elapsed += (s, e) => ReselectItem();
    }

    private void ReselectItem()
    {
        Application.Current.Dispatcher.BeginInvoke((Action)(() =>
        {
            // backup values
            int selectedIndex = this.SelectedIndex;
            AccordionSelectionMode mode = this.SelectionMode;

            // deselect
            this.SelectionMode = AccordionSelectionMode.ZeroOrOne; // allow null selection
            this.SelectedItem = null;

            // restore values (reselect)
            this.SelectionMode = mode;
            this.SelectedIndex = selectedIndex;
        }));
        _layoutUpdateTimer.Stop();
    }
}
like image 36
Mike Fuchs Avatar answered Nov 09 '22 07:11

Mike Fuchs