0

I have an expander control in my UWP app with the following code:

<Expander
     Header="A"
     IsExpanded =" True">
     <TextBlock
       Text="Content in A"/>
</Expander>
<Expander
     Header="B">
     <TextBlock
       Text="Content in B"/>
</Expander>

Currently expander A is expanded by default and B is closed. However, when I expand B, A is also open. I would like the behavior that if I expand one , the other closes and vice versa. Any suggestions as to how I can achieve this in an MVVM way ? Would i need to use converters here? I looked into Collapse all the expanders and expand one of them by default but most of the solutions happen to be in modifying the code behind. How do i achieve the same if i have a XAML code in Main.xaml and i have a corresponding MainPageViewModel.cs?

novice_coder
  • 147
  • 2
  • 10

1 Answers1

0

I would like the behavior that if I expand one , the other closes and vice versa.

For this scenario, you could use OppositConverter to make the other expender close when previous is open.

public class OppositConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
  
        return !(bool)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        return !(bool)value;
    }
}
public class MainPageViewModel : INotifyPropertyChanged
{
    public MainPageViewModel()
    {

    }
    private bool _isExpend;

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string name = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
    public bool IsExpend
    {
        get
        {
            return _isExpend;
        }
        set
        {
            _isExpend = value;
            OnPropertyChanged();
        }
    }
}

Usage

<Page.DataContext>
    <local:MainPageViewModel x:Name="ViewModel" />
</Page.DataContext>
<Page.Resources>
    <local:OppositConverter x:Key="OppositConverter" />
</Page.Resources>
<StackPanel>
    <controls:Expander
        x:Name="Expander1"
        Margin="0,0,0,10"
        VerticalAlignment="Top"
        HorizontalContentAlignment="Stretch"
        ExpandDirection="Down"
        Header="This is the header - expander 1"
        IsExpanded="{Binding IsExpend, Mode=TwoWay}">
        <Grid>
            <TextBlock
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Text="This is the expanded content"
                TextWrapping="Wrap" />
        </Grid>
    </controls:Expander>
    <controls:Expander
        x:Name="Expander2"
        Margin="0,0,0,10"
        VerticalAlignment="Top"
        HorizontalContentAlignment="Stretch"
        ExpandDirection="Down"
        Header="This is the header - expander 2"
        IsExpanded="{Binding IsExpend, Converter={StaticResource OppositConverter}, Mode=TwoWay}">
        <Grid>
            <TextBlock
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Text="This is the expanded content"
                TextWrapping="Wrap" />
        </Grid>
    </controls:Expander>     
</StackPanel>
Nico Zhu
  • 32,367
  • 2
  • 15
  • 36
  • Thank you Nico for this example. I modified the above code as follows to get the desired output. In public class MainPageViewModel, i used set { isExpend=value; RaisePropertyChanged(nameof(isExpend))} instead of the onPropertyChanged method. I also modified the xaml file such that the first expander uses the converter and not the second. What is the difference between using the method over RaisePropertyChanged ? When is ConvertBack called here ? – novice_coder Oct 06 '20 at 04:35
  • 1
    There is no difference between `RaisePropertyChanged` and `OnPropertyChanged`. both of them could notify ui update when the property changed. And the only diffecnece is `OnPropertyChanged` will get the property name automatically. – Nico Zhu Oct 06 '20 at 05:24
  • 1
    ConvertBack Modifies the target data before passing it to the source object. This method is called only in TwoWay bindings. – Nico Zhu Oct 06 '20 at 05:25
  • Thank you for this explanation. Can i get help understanding the flow of this code? When is convertback code called here ? when the first expander is open and the second expander is collapsed, and user clicks to open the second expander, how does the first expander collapse ? – novice_coder Oct 06 '20 at 15:08
  • Yep, the two expanders binding the same `IsExpend` property. but the second use Converter to get opposition. when we click the second one `IsExpend` will become true, and this behaviour will invoke `ConvertBack` method to return false. And at this time `IsExpend` value (false) changing will effect the first expander. – Nico Zhu Oct 07 '20 at 02:55
  • Please check[data binding in depth](https://learn.microsoft.com/en-us/windows/uwp/data-binding/data-binding-in-depth) official document . – Nico Zhu Oct 07 '20 at 02:58
  • Yes!! Thank you for all your help – novice_coder Oct 08 '20 at 15:02