0

I have a ListBox, where the list element has a ComboBox, a TextBox and a slider. Depending on the selction of the ComboBox either the TextBox or the slider should be visible.

    <ListBox Name="lstPWM" >
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="80"/>
                    <!-- more definitions -->
                    </Grid.ColumnDefinitions>
                    <ComboBox   ItemsSource="{Binding Path=Gebertyp, Converter={local1:EnumToCollectionConverter}, Mode=OneTime}"
                                SelectedValuePath="Value"
                                DisplayMemberPath="Description"
                                SelectionChanged="PWMTyp_SelectionChanged"
                                SelectedValue="{Binding Path=Gebertyp}" />
                    <TextBox Visibility="{Binding GeberVisible}" Text="{Binding GeberNmr, Mode=TwoWay}"/>
                   
                    <Slider   Visibility="{Binding WertVisible}" Value="{Binding Wert, Mode=TwoWay}"/>
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

The code behind is:

    public partial class MainWindow : Window
    {
       public ObservableCollection<PWMKanal> PWM_col { get; set; } = new();

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            lstPWM.ItemsSource = PWM_col;
            foreach (var item in Board.PWM)  PWM_col.Add(item); //Board.PWM is the data source.
        }
       private void PWMTyp_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox box = sender as ComboBox;           // Finding the line in the ListBox.
            PWMKanal PWM = box.DataContext as PWMKanal;   
            int z = PWM_col.IndexOf(PWM);
            Board.PWM[z].Gebertyp = (QuellePWM)box.SelectedValue;
            if (Board.PWM[z].Gebertyp == QuellePWM.Sender)
            {
                PWM_col[z].GeberVisible = Visibility.Visible; // I thought that i may change the 
                PWM_col[z].WertVisible = Visibility.Hidden;   // ObservableColelction directly
             }                                                // but the display is not updated.
                else                                          // In Debug mode i see, that PWM_coll
             {                                                // is changed as expected, but no effect 
                PWM_col[z].GeberVisible = Visibility.Hidden;  // on the GUI.
                PWM_col[z].WertVisible = Visibility.Visible;
              }
              if (PWM_col.Count != 0) // this code is intended to update the GUI, but every time
              {                       // a new item is added the Selection Change fires again
                  PWM_col.Clear();    // and i get a stack overflow in an endless loop.
                  foreach (var item in Board.PWM) PWM_col.Add(item);
              }
            
        }
    }

The comments describe my approaches and problems:

  1. I change the selected element of the ObservableCollection directly, but this has no effect on GUI. At least tho code doesn't crash.
  2. I clear the list ObservableCollection PWM_col, but then i get an infinite loop: every time an element is added to the list the SelectionChange event fires, calling the routin again. Result is stack overflow.

Now my questions to my approaches:

  1. Is it possible to change an element of an ObservableCollection directly by code, and the display is automatically refreshed?
  2. Is it possible to somehow catch the SelectionChanged event before the handler is executed? Or is it possible to temporary dissable the event?
  3. Any other idear?

Thank you for your help!

Bernd
  • 1
  • Hello Bernd, welcome by StackOverflow. Next time avoid ask multiple questions in the post. This can help you with next questions : [How to ask](https://stackoverflow.com/help/how-to-ask) – Rekshino Apr 16 '21 at 07:20

1 Answers1

0
  1. CollectionChanged does notify, that collection itself, not the single items, is changed. Therefore to see the changes item's property need to implement INotifyPropertyChanged. Also remove Mode=OneTime

  2. You can of course set the flag, that PWMTyp_SelectionChanged is running:

    private bool selChangedIsRunning = false; private void PWMTyp_SelectionChanged(object sender, SelectionChangedEventArgs e) { if(selChangedIsRunning) return; selChangedIsRunning = true; // do stuff .... selChangedIsRunning = false; }

  3. Other idea is - don't use the SelectionChange event, but do bind Slider.Visibility and TextBox.Visibility to the ComboBox.SelectedValue and use value converter to define the Visibilty, also you can use the ConverterParameter.

<ComboBox x:Name="CmbPWMTyp"  ItemsSource="{Binding Path=Gebertyp, Converter={local1:EnumToCollectionConverter}, Mode=OneTime}"
                    SelectedValuePath="Value"
                    DisplayMemberPath="Description"
                    SelectionChanged="PWMTyp_SelectionChanged"
                    SelectedValue="{Binding Path=Gebertyp}" />
<TextBox Visibility="{Binding ElementName=CmbPWMTyp, Path=SelectedValue, Converter={StaticResource YourConverter}, ConverterParameter=TBX}" Text="{Binding GeberNmr, Mode=TwoWay}"/>
<Slider   Visibility="{Binding ElementName=CmbPWMTyp, Path=SelectedValue, Converter={StaticResource YourConverter}, ConverterParameter=SLDR}" Value="{Binding Wert, Mode=TwoWay}"/>

This link can be also very helpful for you: Difference between SelectedItem SelectedValue and SelectedValuePath

Rekshino
  • 6,954
  • 2
  • 19
  • 44