具有共享绑定的多个组合框 - 从框中首次选择后显示错误

本文关键字:选择 错误 显示 绑定 共享 组合 | 更新日期: 2023-09-27 17:56:45

在过去的几天里,我一直被遇到的一个问题难倒了,并希望得到一些帮助来解决这个问题。

我正在开发一个 WPF 应用程序,该应用程序在第一次运行时会提示用户手动将检测到的串行端口分配给任意"通道",在整个应用程序和以后的界面中用于显示数据等。

其中一个关键功能是,一旦在组合框中分配了端口,就不再可以在其他组合框中选择该端口(使用 .ComboBoxItem 类的 IsEnabled 属性)。

我遇到的问题是,虽然最初一切正常 - 每个组合框都已设置,打开下一个会看到上一个选择灰显 - 如果我尝试返回我之前设置的组合框,它会显示一个空下拉列表。看起来下拉列表仍然处于活动状态,但包含项目的窗口尚未正确调整大小。

屏幕截图:

在后续组合框中成功禁用项目

返回到已选中的框会导致空白下拉列表(蓝色圆圈)

下面是组合框的 XAML 代码:

<StackPanel Grid.Column="1" Name="ComboPanel" Margin="5, 20, 5, 5">
            <ComboBox Margin="0, 5, 0, 0" Width="100" Height="25" Name="cboxChannel0"  IsSynchronizedWithCurrentItem="false" ItemsSource="{Binding portCollectionItems, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="0" DropDownOpened="CboxChannel0_DropDownOpened" DropDownClosed="CboxChannel0_DropDownClosed" />
            <ComboBox Margin="0, 5, 0, 0" Width="100" Height="25" Name="cboxChannel1"  IsSynchronizedWithCurrentItem="false" ItemsSource="{Binding portCollectionItems, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="0" DropDownOpened="CboxChannel0_DropDownOpened" DropDownClosed="CboxChannel0_DropDownClosed" />
            <ComboBox Margin="0, 5, 0, 0" Width="100" Height="25" Name="cboxChannel2"  IsSynchronizedWithCurrentItem="false" ItemsSource="{Binding portCollectionItems, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="0" DropDownOpened="CboxChannel0_DropDownOpened" DropDownClosed="CboxChannel0_DropDownClosed" />
            <ComboBox Margin="0, 5, 0, 0" Width="100" Height="25" Name="cboxChannel3"  IsSynchronizedWithCurrentItem="false" ItemsSource="{Binding portCollectionItems, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="0" DropDownOpened="CboxChannel0_DropDownOpened" DropDownClosed="CboxChannel0_DropDownClosed" />
            <ComboBox Margin="0, 5, 0, 0" Width="100" Height="25" Name="cboxChannel4"  IsSynchronizedWithCurrentItem="false" ItemsSource="{Binding portCollectionItems, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="0" DropDownOpened="CboxChannel0_DropDownOpened" DropDownClosed="CboxChannel0_DropDownClosed" />
            <ComboBox Margin="0, 5, 0, 0" Width="100" Height="25" Name="cboxChannel5"  IsSynchronizedWithCurrentItem="false" ItemsSource="{Binding portCollectionItems, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="0" DropDownOpened="CboxChannel0_DropDownOpened" DropDownClosed="CboxChannel0_DropDownClosed" />
            <ComboBox Margin="0, 5, 0, 0" Width="100" Height="25" Name="cboxChannel6"  IsSynchronizedWithCurrentItem="false" ItemsSource="{Binding portCollectionItems, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="0" DropDownOpened="CboxChannel0_DropDownOpened" DropDownClosed="CboxChannel0_DropDownClosed" />
            <ComboBox Margin="0, 5, 0, 0" Width="100" Height="25" Name="cboxChannel7"  IsSynchronizedWithCurrentItem="false" ItemsSource="{Binding portCollectionItems, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="0" DropDownOpened="CboxChannel0_DropDownOpened" DropDownClosed="CboxChannel0_DropDownClosed" />
            <ComboBox Margin="0, 5, 0, 0" Width="100" Height="25" Name="cboxChannel8"  IsSynchronizedWithCurrentItem="false" ItemsSource="{Binding portCollectionItems, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="0" DropDownOpened="CboxChannel0_DropDownOpened" DropDownClosed="CboxChannel0_DropDownClosed" />
            <ComboBox Margin="0, 5, 0, 0" Width="100" Height="25" Name="cboxChannel9"  IsSynchronizedWithCurrentItem="false" ItemsSource="{Binding portCollectionItems, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="0" DropDownOpened="CboxChannel0_DropDownOpened" DropDownClosed="CboxChannel0_DropDownClosed" />
            <ComboBox Margin="0, 5, 0, 0" Width="100" Height="25" Name="cboxChannel10" IsSynchronizedWithCurrentItem="false" ItemsSource="{Binding portCollectionItems, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="0" DropDownOpened="CboxChannel0_DropDownOpened" DropDownClosed="CboxChannel0_DropDownClosed" />
            <ComboBox Margin="0, 5, 0, 0" Width="100" Height="25" Name="cboxChannel11" IsSynchronizedWithCurrentItem="false" ItemsSource="{Binding portCollectionItems, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="0" DropDownOpened="CboxChannel0_DropDownOpened" DropDownClosed="CboxChannel0_DropDownClosed" />
        </StackPanel>

以下是与盒子相关的代码片段:

public partial class PortWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public ObservableCollection<ComboBoxItem> portCollectionItems { get; set; }
    public ComboBoxItem selectedItem;
    public bool serialPortsSet { get; set; }
    public ComboBoxItem SelectedItem 
    {
        get { return selectedItem; }
        set 
        { 
            if (selectedItem == value) 
                return;
            selectedItem = value;
            OnPropertyChanged("IsEnabled");
        }
    }
    public PortWindow()
    {
        InitializeComponent();
        DataContext    = this;
        serialPortsSet = false;
        portCollectionItems = new ObservableCollection<ComboBoxItem>();
        for (int i = 0; i < ActiveSerialPorts.DetectedPorts.Count(); i++)
        {
            if (i == 0) 
            {
                portCollectionItems.Add(new ComboBoxItem { Content = "<-Select->" });
            }
            portCollectionItems.Add(new ComboBoxItem { Content = ActiveSerialPorts.DetectedPorts[i] }); // Populates collection with a list of serial port names from another class 
        }
    }
    void CboxChannel0_DropDownOpened(object sender, EventArgs e)
    {
        ComboBox comboBox     = sender as ComboBox;
        string selectedString = comboBox.SelectionBoxItem as string;
        selectedItem          = comboBox.SelectedItem as ComboBoxItem;
        foreach (ComboBoxItem portItems in portCollectionItems) 
        {
            if (portItems.Content == selectedItem.Content) 
            {
                portItems.IsEnabled = true; //re-enables the previously disabled selection in case the assigned port needs changing
            }
        }
    }
    void CboxChannel0_DropDownClosed(object sender, EventArgs e)
    {
        ComboBox comboBox = sender as ComboBox;
        selectedItem      = comboBox.SelectedItem as ComboBoxItem;
        string itemString = selectedItem.Content.ToString();
        if (!itemString.Contains("<-Select->"))
        {
            foreach (ComboBoxItem portItems in portCollectionItems) 
            {
                if (portItems.Content == selectedItem.Content) 
                {
                    portItems.IsEnabled = false; // disables the selected item in the observable collection 
                    return;
                }
            }  
        }
    }
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

倾向于相信在绑定方面我缺少一些小而重要的东西。我最初认为是共享集合中的属性更改导致了问题,但在暂停处理程序中的所有代码并运行它后,问题仍然存在。

任何帮助将不胜感激!

具有共享绑定的多个组合框 - 从框中首次选择后显示错误

您正在不同的组合框之间共享组合框项。这些是视觉元素,您正在尝试在不同的父母之间分享它们。我并不惊讶它破裂了。

您需要每个组合框具有不同的组合框项实例集合。您可以最简单的方法是将项目公开为ObservableCollection<String>并让每个组合框创建自己的组合框项。以与绑定集合相同的方式绑定集合;我认为声明和填充该集合几乎应该是您需要进行的唯一更改,除非您需要一次禁用所有框的端口项,而不仅仅是选择它们的端口项。不过,您在组合框上的SelectedItem将是字符串,而不是"ComboBoxItem",因此这些循环的内脏必须稍微改变一下。

当您禁用组合框项时,它自然只会对它所属的组合框禁用。如果你想对所有盒子禁用COM4,你必须循环这样做。

或者你可以再做一点 MVVM:如果这是我,我会在绑定到某个具有 SelectedPort 属性的类的集合的模板化 ItemsControl 中创建一系列组合框,并且我也会为项目使用自定义类,只是一个简单的事情与String PortNamebool IsPortEnabled。我会将IsPortEnabled绑定到 XAML 中的ComboBoxItem.IsEnabled。代码会少得多,但从概念上讲,这是一个很大的飞跃。如果您有兴趣,我们可以去那里。