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:
- I change the selected element of the
ObservableCollectiondirectly, but this has no effect on GUI. At least tho code doesn't crash. - I clear the list
ObservableCollection PWM_col, but then i get an infinite loop: every time an element is added to the list theSelectionChangeevent fires, calling the routin again. Result is stack overflow.
Now my questions to my approaches:
- Is it possible to change an element of an
ObservableCollectiondirectly by code, and the display is automatically refreshed? - Is it possible to somehow catch the
SelectionChangedevent before the handler is executed? Or is it possible to temporary dissable the event? - Any other idear?
Thank you for your help!
CollectionChangeddoes notify, that collection itself, not the single items, is changed. Therefore to see the changes item's property need to implementINotifyPropertyChanged. Also removeMode=OneTimeYou can of course set the flag, that
PWMTyp_SelectionChangedis running:private bool selChangedIsRunning = false; private void PWMTyp_SelectionChanged(object sender, SelectionChangedEventArgs e) { if(selChangedIsRunning) return; selChangedIsRunning = true; // do stuff .... selChangedIsRunning = false; }
Other idea is - don't use the
SelectionChangeevent, but do bindSlider.VisibilityandTextBox.Visibilityto theComboBox.SelectedValueand use value converter to define theVisibilty, also you can use theConverterParameter.This link can be also very helpful for you: Difference between SelectedItem SelectedValue and SelectedValuePath