WPF ComboBox привязан к коллекции пользовательских элементов управления, не отображающих текст выбранного элемента - PullRequest
0 голосов
/ 22 июня 2010

У меня есть ComboBox, который связан с ObservableCollection пользовательских UserControls. Каждому пользовательскому элементу управления присвоено значение Tag, а для ComboBox DisplayMemberPath установлено значение «Tag». Это правильно отображает тег каждого элемента UserControl в раскрывающемся списке при щелчке ComboBox, однако, когда элемент в списке выбран и раскрывающийся список закрыт, ComboBox ничего не отображает в кнопке.

Если я поменяю UserControl на стандартный элемент управления WPF, такой как TextBox, то он правильно отображает значение тега выбранного элемента, поэтому это связано с привязкой к UserControl против стандартного элемента управления WPF. Кроме того, если для свойства IsEditable задано значение True, редактируемый текстовый блок корректно отображает тег, но я не хочу, чтобы текст был редактируемым.

Как заставить выбранный элемент отображаться, когда ComboBox не раскрыт?

Вот пример кода, который повторяет проблему:

(Примечание. Пример кода взят из контекста приложения, в котором он запущен, поэтому он выглядит немного странно в том, что пытается сделать, но все равно приводит к тем же симптомам).

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 с раскрывающимся списком http://img229.imageshack.us/img229/5597/comboboxtestexpanded.png

И когда выбран «UC 2», он выглядит как: ComboBox с невидимым выбранным элементом http://img692.imageshack.us/img692/4362/comboboxtestuc2selected.png

1 Ответ

1 голос
/ 22 июня 2010

Привязка списка 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; }
    }
}
...