问题描述
我有一个 ListBox,其中的列表元素有一个 ComboBox、一个 TextBox 和一个滑块。根据 ComboBox 的选择,TextBox 或滑块应该可见。
<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>
背后的代码是:
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);
}
}
}
- 我直接更改了
ObservableCollection
的选定元素,但这对 GUI 没有影响。至少代码不会崩溃。 - 我清除了列表
ObservableCollection PWM_col
,但随后出现了无限循环:每次将元素添加到列表中时,SelectionChange
事件都会触发,再次调用例程。结果是堆栈溢出。
现在我对我的方法的问题:
- 是否可以直接通过代码更改
ObservableCollection
的某个元素,并自动刷新显示? - 是否有可能在处理程序执行之前以某种方式捕获
SelectionChanged
事件?或者是否可以暂时禁用该事件? - 还有其他想法吗?
感谢您的帮助!
解决方法
-
CollectionChanged
确实通知了该集合本身,而不是 单品,变了。因此要查看更改项的 属性需要实现INotifyPropertyChanged
。同时删除Mode=OneTime
-
您当然可以设置标志,即
PWMTyp_SelectionChanged
是 运行:private bool selChangedIsRunning = false; 私有无效PWMTyp_SelectionChanged(对象发送者,SelectionChangedEventArgs e) { 如果(selChangedIsRunning)返回; selChangedIsRunning = true; // 做东西 .... selChangedIsRunning = false; }
-
其他想法是 - 不要使用
SelectionChange
事件,但要绑定Slider.Visibility
和TextBox.Visibility
到ComboBox.SelectedValue
并使用值转换器来定义Visibilty
,您也可以使用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,ConverterParameter=SLDR}" Value="{Binding Wert,Mode=TwoWay}"/>
此链接对您也很有帮助:Difference between SelectedItem SelectedValue and SelectedValuePath