XAML/WPF: How to get XAML to re-evaluate when using a ComboBox in a ListView

Hi,

I'm finding it tricky to find an answer for this as maybe I'm not wording my searches correctly.

I've got some fairly simple XAML whichs presents ListView items based on a class which uses the usual ObservableCollection and INotifyChanged.

ListView Combo drop down
Above you see one row in the Grid and the "Channel" combo is open with the options. You can't see it clearly (this is another problem I've got) but the last 8 items are actually disabled - only the first 4 items are enabled. Also the row itself is difficult to see - too bright - which is ANOTHER problem I have (asked separately but no answers as yet).

The XAML takes care of the enable/disable status depending on if the "Mode" combo is "Stereo" or "Mono". If "Stereo" is selected then the first 4 items are enabled and the rest are disabled.

I want the selection of "Mono" to do the opposite - disable the first 4 items and enable the rest.

My question is, how do I get the XAML to re-evaluate the "Channel" ComboBox? Or do I need to manage this in the code somehow?

Here's the ListView code.

                                    <ListView x:Name="ListViewOutputs" Style="{DynamicResource StyleListView}">
                                        <ListView.View>
                                            <GridView>
                                                <GridViewColumn Header="Enabled">
                                                    <GridViewColumn.CellTemplate>
                                                        <DataTemplate>
                                                            <CheckBox IsChecked="{Binding Enabled, Mode=TwoWay}" Style="{DynamicResource StyleCheckBox}"/>
                                                        </DataTemplate>
                                                    </GridViewColumn.CellTemplate>
                                                </GridViewColumn>
                                                <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
                                                <GridViewColumn Header="Mode">
                                                    <GridViewColumn.CellTemplate>
                                                        <DataTemplate>
                                                            <ComboBox x:Name="ComboBoxOutputMode" SelectionChanged="ComboBoxOutputMode_SelectionChanged" SelectedValuePath="Content" SelectedValue="{Binding Mode, Mode=TwoWay}" Style="{DynamicResource ComboBoxStyle}">
                                                                <ComboBoxItem Content="Stereo"/>
                                                                <ComboBoxItem Content="Mono"/>
                                                            </ComboBox>
                                                        </DataTemplate>
                                                    </GridViewColumn.CellTemplate>
                                                </GridViewColumn>
                                                <GridViewColumn Header="Monitor">
                                                    <GridViewColumn.CellTemplate>
                                                        <DataTemplate>
                                                            <CheckBox IsChecked="{Binding Monitor, Mode=TwoWay}" Style="{DynamicResource StyleCheckBox}"/>
                                                        </DataTemplate>
                                                    </GridViewColumn.CellTemplate>
                                                </GridViewColumn>
                                                <GridViewColumn Header="Channel">
                                                    <GridViewColumn.CellTemplate>
                                                        <DataTemplate>
                                                            <ComboBox x:Name="ComboBoxOutputChannel" DropDownOpened="ComboBoxOutputChannel_DropDownOpened"  SelectedValuePath="Content" SelectedValue="{Binding ChannelString, Mode=TwoWay}" Style="{DynamicResource ComboBoxStyle}">
                                                                <ComboBoxItem IsEnabled="{Binding IsModeStereo}" Content="Front"/>
                                                                <ComboBoxItem IsEnabled="{Binding IsModeStereo}" Content="Rear"/>
                                                                <ComboBoxItem IsEnabled="{Binding IsModeStereo}" Content="Center/Subwoofer"/>
                                                                <ComboBoxItem IsEnabled="{Binding IsModeStereo}" Content="Side"/>
                                                                <ComboBoxItem IsEnabled="{Binding IsModeMono}" Content="Front Left"/>
                                                                <ComboBoxItem IsEnabled="{Binding IsModeMono}" Content="Front Right"/>
                                                                <ComboBoxItem IsEnabled="{Binding IsModeMono}" Content="Rear Left"/>
                                                                <ComboBoxItem IsEnabled="{Binding IsModeMono}" Content="Rear Right"/>
                                                                <ComboBoxItem IsEnabled="{Binding IsModeMono}" Content="Center"/>
                                                                <ComboBoxItem IsEnabled="{Binding IsModeMono}" Content="Subwoofer"/>
                                                                <ComboBoxItem IsEnabled="{Binding IsModeMono}" Content="Side Left"/>
                                                                <ComboBoxItem IsEnabled="{Binding IsModeMono}" Content="Side Right"/>
                                                            </ComboBox>
                                                        </DataTemplate>
                                                    </GridViewColumn.CellTemplate>
                                                </GridViewColumn>
                                                <GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}"/>
                                            </GridView>
                                        </ListView.View>
                                    </ListView>

Open in new window

Matt CartlidgeSenior Infrastructure EngineerAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ambienceCommented:
Line 37 is where the combobox item is bound to the IsModeMono property. Can you post the code behind class especially the implementation of the IsModeMono property?

There are three ways for IsModeStereo/IsModeMono to trigger update of the UI. (re-evaluate)

1- If these are DependencyProperties
2- An event of the same name IsModeStereoChanged is fired from property setter
3- INotifyPropertyChanged is implemented by the object. This is similar to 2 but uses a single OnPropertyChanged event for all bound properties

Another possibility, and arguably cleaner approach would be to create a ValueConverter that converts value of the combobox to Boolean. Then you can bind the IsEnabled directly to the Combobox control - instead of having to define properties on the ViewModel like IsModeStereo. Here is what it may look like

    <ComboBoxItem IsEnabled="{Binding ElementName=ComboBoxOutputMode, Path=Value, Converter={StaticResource MyConvertModeToBoolean}}" Content="Side Right"/>

For more info see: https://www.codeproject.com/Articles/418271/Custom-Value-Conversion-in-WPF

or google "Custom Value converters in WPF"
1
Matt CartlidgeSenior Infrastructure EngineerAuthor Commented:
Thanks for your response.

It is becoming clearer now why this isn't working as I'd expect.

My code for the IsModeStereo method :-

        public bool IsModeStereo
        {
            get
            {
                if (Mode == MCOutputMode.Stereo) { return true; }
                return false;
            }
        }

Open in new window


You can probably guess what the IsModeMono method looks like so I won't post that.

This is the MCOutputMode which determines the result of IsModeMono and IsModeStereo.

        private MCOutputMode _Mode;
        public MCOutputMode Mode
        {
            get { return _Mode; }
            set
            {
                _Mode = value;
                OnPropertyChanged();
            }
        }

Open in new window


I've added the OnPropertyChanged() call for both IsModeMono and IsModeStereo. However, this causes an overflow, assuming because  they are stuck in a loop calling eachother.

Can you see what I'm doing wrong here? Happy to share more code if you think it's relevant.
0
ambienceCommented:
Overflow is due to infinite recursion. Place a breakpoint and see why its happening.  Without access to all the code its hard to say whats going on. Here is an example of one way of doing it.

public class Foo : INotifyPropertyChanged
{

  MCOutputMode _mode;
  public MCOutputMode Mode
  {
    get { return _mode; }
    set
    {
      _mode = value;
      NotifyPropertyChanged();
      NotifyPropertyChanged(nameof(this.IsModeStereo));
      NotifyPropertyChanged(nameof(this.IsModeMono));
    }
  }

  public bool IsModeStereo => Mode == MCOutputMode.Stereo;
  public bool IsModeMono => Mode == MCOutputMode.Mono;

  public event PropertyChangedEventHandler PropertyChanged;

  private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
  {
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  }
}

Open in new window

1

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

Matt CartlidgeSenior Infrastructure EngineerAuthor Commented:
Works great! Thank you!

What is the purpose of => ?

I haven't seen that used before, but I am relatively new to C#
0
Matt CartlidgeSenior Infrastructure EngineerAuthor Commented:
All sorted, thanks!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
WPF

From novice to tech pro — start learning today.