14

I have an Expander control with its IsExpanded property bound to a bool in the mvvm model. The binding works fine until you dont touch the expander. Once you click the arrow in the expander to expand, the binding stops working. Setting the bool ShowPreview to false in the model doesn't collapse the expander.

<Expander Name="pExpander" 
          IsExpanded="{Binding Path=ShowPreview,Mode=OneWay}"
          Header="Preview">
    <TextBlock Text="{Binding Path=Message, Mode=OneWay}"></TextBlock>    
</Expander>
Brandon
  • 16,382
  • 12
  • 55
  • 88
netraju
  • 141
  • 1
  • 1
  • 5
  • Does your object with property ShowPreview implement the INotifyPropertyChanged interface and raise the event when your property is changed? – mattythomas2000 Feb 01 '10 at 22:31
  • 1
    Binding Mode should be TwoWay. As soon as you expand on the expander, the OneWay binding collapses and expansion is framework controlled. – apandit Feb 02 '10 at 02:12
  • Thanks! TwoWay works. But why can't it work oneway? I am only interested in the model controlling the expansion and collapse based on an external event which sets it to true or false. If the framework expands or collapses the expander I am not interested in that value being set back in the model. – netraju Feb 02 '10 at 19:23
  • If you're not interested in bringing it back, you can have two properties: one for binding and one for determining expansion. The thing with OneWay binding is that if the framework makes changes to the binded property, the binding collapses (ie. no longer applicable). Try putting a one way binding on a Textbox then letting a user edit it, for example. As soon as the user puts in some new data, even if trigger the binding source the textbox won't update with that value. – apandit Feb 03 '10 at 18:55

5 Answers5

7

If you remove Mode=OneWay does that fix the problem?

Upon reading your other CTQ (changes to the GUI do not affect the model), I don't have a good suggestion for how to limit the change being seen by the underlying data. What is the difference in:

myModel.MyProperty = true; // in *your* code behind

And

myModel.MyProperty = true; // done by a binding
user7116
  • 63,008
  • 17
  • 141
  • 172
7

What caught me out here is that IsExpanded is OneWay by default, so

<Style TargetType="TreeViewItem">
    <Setter Property="IsExpanded" Value="{Binding Expanded}"/>
</Style>

doesn't work the way I expected. Only if you add Mode=TwoWay, then it works (i.e. the item starts paying attention to my Expanded property, and updating it), as in

<Style TargetType="TreeViewItem">
    <Setter Property="IsExpanded" Value="{Binding Expanded, Mode=TwoWay}"/>
</Style>
Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
imekon
  • 1,501
  • 4
  • 22
  • 39
1

With Silverlight I do this:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"

<Expander Name="pExpander" IsExpanded="True" Header="Preview">
    <i:Interaction.Triggers>
        <ei:PropertyChangedTrigger Binding="{Binding ShowPreview, Mode=OneWay}">
            <ei:ChangePropertyAction PropertyName="IsExpanded" Value="{Binding ShowPreview, Mode=OneWay}"/>
        </ei:PropertyChangedTrigger>
    </i:Interaction.Triggers>
    <TextBlock Text="{Binding Path=Message, Mode=OneWay}"></TextBlock>    
</Expander>
<Expander Name="pExpander1" IsExpanded="True" Header="Preview 1">
    <i:Interaction.Triggers>
        <ei:PropertyChangedTrigger Binding="{Binding ShowPreview, Mode=OneWay}">
            <ei:ChangePropertyAction PropertyName="IsExpanded" Value="{Binding ShowPreview, Mode=OneWay}"/>
        </ei:PropertyChangedTrigger>
    </i:Interaction.Triggers>
    <TextBlock Text="{Binding Path=Message1, Mode=OneWay}"></TextBlock>    
</Expander>
//...

The binding is not lost when you manualy expand/collapse one Expander...

Adi Lester
  • 24,731
  • 12
  • 95
  • 110
Tonio
  • 743
  • 1
  • 4
  • 18
  • The only thing I had to change for wpf was in the propertychangedtrigger and value options, Binding Path=ShowPreview. Other than that, this was perfect for me, thank you. – Jake Gaston Apr 29 '14 at 22:27
0

Do three things,

Make sure your ViewModel is implementing INotifyPropertyChanged. Your ui wont know about the change if your view model doesnt inform it when the property changes

Change the Mode to TwoWay, you want your view model updated when the expander changes and you want your expander updated when the view model changes

Lastly if the above two don't work use a debug converter to ascertain if your binding is failing. there is an example here of how to do this. This is a technique every wpf developer needs.

I know there was an issue with radio buttons that they would lose their bindings when another button in the group was set, i don't think that is the issue here, however a debug converter will help you figure this out.

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Aran Mulholland
  • 23,555
  • 29
  • 141
  • 228
  • Thanks for the replies. Yes the Model does implement INotifyPropertyChanged. The binding works fine as long as you don't touch the expander. As soon as you mouse click on the expander to expand, the binding doesn't work anymore. In debug you can see that IsExpanded is getting set to either true or false. But visually the expander stays expanded. – netraju Feb 02 '10 at 16:43
  • if you put the debug converter on, does the debug converter keep getting hit every time you change the collapsed state? – Aran Mulholland Feb 02 '10 at 22:29
0

In my case (.NET Framework 4) the setter for the expanded wasn't called, because its binding required UpdateSourceTrigger=PropertyChanged, and setting Mode=TwoWay (as proposed in other answer) couldn't solve this issue.
I've ended up with following XAML:

<Expander x:Name="GroupExpander"
          IsExpanded="{Binding IsExpanded, UpdateSourceTrigger=PropertyChanged}"/>

My Expander is in a DataGridTemplateColumn (in a row).

AntonK
  • 1,210
  • 1
  • 16
  • 22