ComboBox SelectedIndex 绑定 -1 或 0 不选择第一项

Posted

技术标签:

【中文标题】ComboBox SelectedIndex 绑定 -1 或 0 不选择第一项【英文标题】:ComboBox SelectedIndex Binding -1 or 0 not selecting first item 【发布时间】:2021-04-01 00:35:13 【问题描述】:

我有一个ComboBox,它会在SelectedItem 更改时写入配置文件。 我想使用SelectedIndex = -1 作为备用,以防SelectedItem 丢失。

我不希望SelectedIndex 在程序启动时触发并写入配置文件,所以我将事件处理程序放在C# Window_Loaded() 而不是XAML


问题是Video_SelectedIndex = -1 没有选择任何内容,它使SelectedItem 留空。


主窗口

private void Window_Loaded(object sender, RoutedEventArgs e)

    cboPlugin_Video.SelectedIndex += VM.PluginsView.Video_SelectedIndex; // <-- Problem here
    cboPlugin_Video.SelectionChanged += cboPlugin_Video_SelectionChanged;

我试图以另一种方式绑定它,但它在程序启动时触发。

cboPlugin_Video.DataContext = VM.PluginsView;
Binding Plugins_Video_SelectedIndexBinding = new Binding()  Source = VM.PluginsView, Path = new PropertyPath("Video_SelectedIndex"), Mode = BindingMode.TwoWay ;
cboPlugin_Video.SetBinding(ComboBox.SelectedIndexProperty, Plugins_Video_SelectedIndexBinding);

XAML

<Window.DataContext>
    <local:VM/>
</Window.DataContext>

<ComboBox x:Name="cboPlugin_Video"
          DataContext="Binding PluginsView"
          ItemsSource="Binding Video_Items"
          SelectedItem="Binding Video_SelectedItem"
          Margin="10,12,0,0"
          VerticalAlignment="Top"
          Height="22" 
          HorizontalAlignment="Left" 
          Width="140" />

视图模型

namespace ViewModel

    public class PluginsViewModel : INotifyPropertyChanged
    
        public event PropertyChangedEventHandler PropertyChanged = delegate  ;
        private void OnPropertyChanged(string prop)
        
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            
                handler(this, new PropertyChangedEventArgs(prop));
            
        

        private int _Video_SelectedIndex  get; set; 
        public int Video_SelectedIndex
        
            get  return _Video_SelectedIndex; 
            set
            
                if (_Video_SelectedIndex == value)
                
                    return;
                

                _Video_SelectedIndex = value;
                OnPropertyChanged("Video_SelectedIndex");
            
        

选择项目/索引

// Plugin Found
if (test == "Example")

    VM.PluginsView.Video_SelectedItem = "Example"; // Works


// Missing, Default to First Item
else

    VM.PluginsView.Video_SelectedIndex = -1; // <-- Not working

选择更改事件

private void cboPlugin_Video_SelectionChanged(object sender, SelectionChangedEventArgs e)

    // Write to config file
    // Works

【问题讨论】:

The problem is Video_SelectedIndex = -1 doesn't select anything, it leaves the SelectedItem blank. 有错字吗? cboPlugin_Video.SelectedIndex += VM.PluginsView.Video_SelectedIndex; - 不应该只是= 而不是+= 吗? @RandRandom 它看起来像 +=-1 而不是 0 是问题所在,但在将其更改为 = 后,它现在在启动时触发。 @RandRandom 我认为我不能正确地将它绑定到 ViewModel。我想我必须将MainWindow 传递给它并使用mainwindow.cboPlugin_Video.SelectedIndex = 0 您可以在ContentRendered 上注册SelectionChanged 事件而不是加载docs.microsoft.com/en-us/dotnet/api/… - 这应该在所有绑定评估后发生 【参考方案1】:

期待评论

你为什么不在你的 setter 中写配置?

private int _Video_SelectedIndex  get; set; 
public int Video_SelectedIndex

    get  return _Video_SelectedIndex; 
    set
    
        if (_Video_SelectedIndex == value)
        
            return;
        

        _Video_SelectedIndex = value;
        OnPropertyChanged("Video_SelectedIndex");

       //write to config
    

这样您就不会将SelectionChange 从无 (-1) 变为 0,因为 _Video_SelectedIndex 将使用 0 进行初始化,如果 if (_Video_SelectedIndex == value)0 更改为 @987654326 将阻止触发@。

顺便说一句,您为什么将_Video_SelectedIndex 声明为属性而不是字段?

为什么会这样:

private int _Video_SelectedIndex  get; set; 

而不是

private int _Video_SelectedIndex;

编辑:

我无法重现你的问题,也许我做的这个小测试项目会对你有所帮助。

如果不是,请进行必要的更改以显示您的问题。

注意,我已经测试了SelectedIndexSelectedItem

MainWindow.xaml

<Window x:Class="WpfApp10.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApp10">
    <Window.DataContext>
        <local:MyViewModel />
    </Window.DataContext>
    <StackPanel Orientation="Vertical">
        <TextBlock Text="ComboBox with SelectedItem" />
        <ComboBox ItemsSource="Binding Items" SelectedItem="Binding SelectedItem" />

        <TextBlock Text="ComboBox with SelectedIndex" />
        <ComboBox ItemsSource="Binding Items" SelectedIndex="Binding SelectedIndex" />
    </StackPanel>
</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window

    public MainWindow()
    
        InitializeComponent();
    

MyViewModel.cs

public class MyViewModel : INotifyPropertyChanged

    private Config _config;
    private string _selectedItem;
    private int _selectedIndex;
    
    public event PropertyChangedEventHandler? PropertyChanged;

    public IEnumerable<string> Items  get; set;  = Enumerable.Range(0, 10).Select(x => $"Foo x");

    public string SelectedItem
    
        get => _selectedItem;
        set
        
            if (_selectedItem == value)
                return;
            
            _selectedItem = value;
            OnPropertyChanged();
            
            //write config
            _config.SelectedItem = value;
        
    
    public int SelectedIndex
    
        get => _selectedIndex;
        set
        
            if (_selectedIndex == value)
                return;
            
            _selectedIndex = value;
            OnPropertyChanged();
            
            //write config
            _config.SelectedIndex = value;
        
    

    public MyViewModel()
    
        _config = new Config();
        
        //read config
        _selectedItem = _config.SelectedItem;
        _selectedIndex = _config.SelectedIndex;
    

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    

Config.cs

public class Config

    public string SelectedItem  get; set; 
    public int SelectedIndex  get; set; 

    public Config()
    
        //fake reading stuff from *.config file
        
        //test it with either of those
        
        //SelectedItem = "Foo 2";
        //SelectedIndex = 2;

        SelectedItem = null;
        SelectedIndex = -1;
    

//write config 两个部分仅在用户手动更改组合框值时才会命中,而不是在启动时自动命中。

如果配置返回null-1,要使用默认值,您可以更改此代码:

//read config
_selectedItem = _config.SelectedItem;
_selectedIndex = _config.SelectedIndex;

到这里:

//read config
_selectedItem = _config.SelectedItem ?? Items.First();
_selectedIndex = _config.SelectedIndex == -1 ? 0 : _config.SelectedIndex;

或者要准确检查存储在_config 中的值是否仍然有效,您可以使用它

_selectedItem = Items.Contains(_config.SelectedItem) ? _config.SelectedItem : Items.First();
_selectedIndex = _config.SelectedIndex >= Items.Count() || _config.SelectedIndex < 0 ? 0 : _config.SelectedIndex;

【讨论】:

我尝试在设置器中写入配置,但绑定SelectedIndex 仍然在启动时触发,我尝试了任何方式。 get; set; 可能是我所关注的示例中的意外。 @MattMcManis - 你的问题解决了吗?【参考方案2】:

值 -1 表示没有选择任何元素。您必须将其设置为 0 才能获得第一项。

如此处所述:

https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.combobox.selectedindex?view=net-5.0

【讨论】:

以上是关于ComboBox SelectedIndex 绑定 -1 或 0 不选择第一项的主要内容,如果未能解决你的问题,请参考以下文章

datatable绑定comboBox,在下拉菜单中显示对应数据

C# ComboBox枚举量绑定的 两种方法

WPF中ComboBox绑定数据库自动读取产生数据

C# 如果获得combobox的下拉表中有多少项(Items)

WinForm ComboBox SelectedValue 属性与 SelectedIndex

使用选定的文本而不是 selectedIndex