WPF ComboBox 绑定到不显示所选项目文本的用户控件集合

Posted

技术标签:

【中文标题】WPF ComboBox 绑定到不显示所选项目文本的用户控件集合【英文标题】:WPF ComboBox Bound to Collection of UserControls Not Showing Selected Item's Text 【发布时间】:2011-03-06 16:05:49 【问题描述】:

我有一个绑定到自定义 UserControls 的 ObservableCollection 的 ComboBox。每个用户控件都有一个 Tag 值集,并且 ComboBox 的 DisplayMemberPath 设置为“Tag”。当单击ComboBox时,这会正确显示下拉列表中的每个UserControl的标记,但是选择列表中的项目并关闭下拉列表时,ComboBox在按钮中显示任何内容。

如果我将 UserControl 替换为标准 WPF 控件(例如 TextBox),那么它会正确显示所选项目的 Tag 值,因此它与绑定到 UserControl 与标准 WPF 控件有关。另外,如果我将 IsEditable 设置为 True,则可编辑的 TextBox 会正确显示标签,但我不希望文本可编辑。

如何在 ComboBox 未展开时显示 Selected 项?

这里是一些复制问题的示例代码:

(注意:示例代码是从它运行的应用程序的上下文中取出的,因此它尝试执行的操作看起来有点奇怪,但仍然会导致相同的症状)。

MyUC.xaml

<UserControl x:Class="ComboboxTest.MyUC"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <TextBox />
    </Grid>
</UserControl>

Window1.xaml

<Window x:Class="ComboboxTest.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ComboboxTest"
        Title="Window1" Height="300" Width="300"
        DataContext="Binding RelativeSource=RelativeSource Self">
<StackPanel>
    <StackPanel Name="ControlsHolder">
        <TextBox Tag="Box 1" Text="This is in Box 1" />
        <TextBox Tag="Box 2" Text="This is in Box 2" />
        <local:MyUC Tag="UC 1" />
        <local:MyUC Tag="UC 2" />
    </StackPanel>
    <Grid>
        <ComboBox Grid.Column="1" 
              Margin="5,0" 
              Name="MyComboBox" 
              ItemsSource="Binding MyControls"
              DisplayMemberPath="Tag" 
              MinWidth="120"/>
    </Grid>
</StackPanel>

Window1.cs

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;

namespace ComboboxTest

    public partial class Window1 : Window, INotifyPropertyChanged
    
        ObservableCollection<MyUC> myControls = new ObservableCollection<MyUC>();

        public Window1()
        
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(Window1_Loaded);
        

        void Window1_Loaded(object sender, RoutedEventArgs e)
        
            myControls.Clear();

            foreach (UIElement uiElement in this.ControlsHolder.Children)
            
                MyUC tb = uiElement as MyUC;

                if (tb != null)
                
                    myControls.Add(tb);
                
            

            RaisePropertyChanged("MyControls");
        

        public ObservableCollection<MyUC> MyControls
        
            get
            
                return this.myControls;
            
        

        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string p)
        
            if (PropertyChanged != null)
            
                PropertyChanged(this, new PropertyChangedEventArgs(p));
            
        
    

此应用显示为: ComboBox with Drop Down Visible http://img229.imageshack.us/img229/5597/comboboxtestexpanded.png

以及选择“UC 2”时,它显示为: ComboBox with selected item not visible http://img692.imageshack.us/img692/4362/comboboxtestuc2selected.png

【问题讨论】:

【参考方案1】:

绑定UIElements 列表不是一个好主意。尝试使用包装类:

public partial class Window1 : Window

    public Window1()
    
        InitializeComponent();
        this.Loaded += new RoutedEventHandler(Window1_Loaded);
        MyComboBox.ItemsSource = MyControls;
    

    ObservableCollection<Wrapper> myControls = new ObservableCollection<Wrapper>();

    void Window1_Loaded(object sender, RoutedEventArgs e)
    
        myControls.Clear();

        foreach (UIElement uiElement in this.ControlsHolder.Children)
        
            MyUC tb = uiElement as MyUC;

            if (tb != null)
            
                myControls.Add(new Wrapper(tb));
            
        

        RaisePropertyChanged("MyControls");
    

    public ObservableCollection<Wrapper> MyControls
    
        get
        
            return this.myControls;
        
    

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string p)
    
        if (PropertyChanged != null)
        
            PropertyChanged(this, new PropertyChangedEventArgs(p));
        
    


public class Wrapper

    public UserControl Control  get; protected set; 

    public Wrapper(UserControl control)
    
        Control = control;
    

    public Object Tag
    
        get  return Control.Tag; 
    

【讨论】:

感谢 decyclone,成功了。但是你有没有解释为什么将它包装在另一个类中,以及为什么绑定到 UIElement 是一个坏主意? 通过将 UserControls 添加到 ItemsSource,它们不会成为 ComboBox 的 VisualTree 的一部分。 ItemsSource 中的每个对象都使用 ComboBoxItem 进行包装。这就是为什么它们在 ComboBox 中不能很好地显示的原因。在使用 ItemsSource 绑定时,建议使用类而不是 UIElements。 我很惊讶地发现有人遇到了完全相同的问题。创建实用程序以在 Prism 模块(即用户控件)上设置 Active Directory 组权限。想让用户选择要设置权限的模块。如果他们不显示,那就危险了!谢谢!

以上是关于WPF ComboBox 绑定到不显示所选项目文本的用户控件集合的主要内容,如果未能解决你的问题,请参考以下文章

所选项目 ComboBox 未显示正确的 ID WPF

WPF Combobox在窗口加载后未显示所选项目

Silverlight Combobox 将所选项目设置为 datagrid 的所选项目

在WPF中的Combobox中绑定

WPF DataTemplate ComboBox 绑定问题

WPF ComboBox 最初以错误的大小显示第一个项目