开发者

WPF ComboBox Bound to Collection of UserControls Not Showing Selected Item's Text

I have a ComboBox that is bound to an ObservableCollection of custom UserControls. Each user control has a Tag value set and the ComboBox' DisplayMemberPath is set to "Tag". This correctly displays the Tag of each UserControl in the drop down list when the ComboBox is clicked, however when an item in the list is selected and the drop down list is closed, the ComboBox displays nothing in the button.

If I swap out a UserControl for a standard WPF control such as a TextBox, then it correctly displays the Tag value of the selected item, so it is something related to binding to a UserControl vs a standard WPF control. Also, if I set the IsEditable to True, then the editable TextBox displays the Tag correctly, but I don't want the text to be editable.

How do I get the Selected item to display when the ComboBox is not expanded?

Here is some sample code that replicates the issue:

(Note: The sample code is taken out of the context of the application it is running in so it lo开发者_如何学编程oks a bit weird in what it is trying to do, but it still results in the same symptoms).

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));
            }
        }
    }
}

This app appears as: ComboBox with Drop Down Visible http://img229.imageshack.us/img229/5597/comboboxtestexpanded.png

And when "UC 2" is selected it appears as: ComboBox with selected item not visible http://img692.imageshack.us/img692/4362/comboboxtestuc2selected.png


Binding a list of UIElements is not a good idea. Try using a wrapper class :

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; }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜