Обновление SelectedItem в ItemsControl (ComboBox) в UserControl - PullRequest
0 голосов
/ 26 октября 2011

Перед выбором любого элемента в ComboBox его SelectedItem является нулевым, а сам ComboBox визуально пустым. После того, как что-то выбрано, пользователь, похоже, никак не может выбрать «отсутствие выделения» (хотя это можно сделать, установив SelectedItem в ноль в коде).

Мои ComboBox связаны с ObservableCollections моих объектов. Я не хочу добавлять «специальный» первый нулевой объект в начало каждой коллекции ObservableCollection. Поэтому я пользуюсь этой возможностью, чтобы немного узнать о написании UserControl.

Проблема в том, что SelectedItem работает не так, как обычно. То есть, ComboBox приятно привязан к поддержке ObservableCollection, но выбор чего-то из ComboBox не обновляет SelectedItem, с которым он должен быть связан.

Я чувствую, что мне нужно передать некоторую информацию из ComboBox в UserControl в ... куда-нибудь. Я на правильном пути? Зачем мне гуглить?

C #:

public partial class ClearableComboBox : UserControl
{
    public ClearableComboBox()
    {
        InitializeComponent();
    }

    public IEnumerable ItemsSource
    {
        get { return (IEnumerable)base.GetValue(ItemsSourceProperty); }
        set { base.SetValue(ItemsSourceProperty, value); }
    }

    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register("ItemsSource",
            typeof(IEnumerable),
            typeof(ClearableComboBox));

    public object SelectedItem
    {
        get { return (object)base.GetValue(SelectedItemProperty); }
        set { base.SetValue(SelectedItemProperty, value); }
    }

    public static readonly DependencyProperty SelectedItemProperty =
        DependencyProperty.Register("SelectedItem",
            typeof(object),
            typeof(ClearableComboBox));

    public string DisplayMemberPath
    {
        get { return (string)base.GetValue(DisplayMemberPathProperty); }
        set { base.SetValue(DisplayMemberPathProperty, value); }
    }

    public static readonly DependencyProperty DisplayMemberPathProperty =
        DependencyProperty.Register("DisplayMemberPath",
            typeof(string),
            typeof(ClearableComboBox));

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        comboBox.SelectedItem = null;
    }
}

XAML:

<UserControl x:Class="MyProj.ClearableComboBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             x:Name="root">
    <DockPanel>
        <Button DockPanel.Dock="Left" Click="Button_Click" ToolTip="Clear">
            <Image Source="pack://application:,,,/img/icons/silk/cross.png" Stretch="None" />
        </Button>
        <ComboBox
            Name="comboBox"
            ItemsSource="{Binding ElementName=root, Path=ItemsSource}"
            SelectedItem="{Binding ElementName=root, Path=SelectedItem}"
            DisplayMemberPath="{Binding ElementName=root, Path=DisplayMemberPath}" />
    </DockPanel>
</UserControl>

Использование:

<wpfControl:ClearableComboBox ItemsSource="{Binding Path=Things}"
                              DisplayMemberPath="SomeProperty"
                              SelectedItem="{Binding Path=SelectedThing}" />

// Picking a Thing doesn't update SelectedThing :(

Ответы [ 3 ]

1 голос
/ 27 октября 2011

Поскольку выпадающий список происходит из класса Selector, который, в свою очередь, происходит от ItemsControl. Таким образом, наследуя UserControl, вы добавляете в свой комбинированный список свойства класса Selector, которые могут внутренне обрабатывать объект Selection для вас. поэтому, я бы предложил вместо того, чтобы выводить его из UserControl, вы должны извлечь его из Combobox, как это -

public partial class ClearableComboBox : ComboBox

Таким образом, таким образом вам не придется переопределять ItemsSource, DisplayMemberPath и т. Д. В вашем классе, поскольку он уже присутствует в классе ComboBox. Вы всегда можете расширить свой класс, чтобы обеспечить дополнительные функции, которые в вашем случае устанавливают значение SelectedItem равным нулю при некотором нажатии кнопки. Надеюсь, это то, что вы хотите ..

РЕДАКТИРОВАТЬ (пользовательский контроль)

Создание пользовательского элемента управления - это ваш ответ, для начала, если вы не знаете об этом, посмотрите на это для начала - http://www.wpftutorial.net/HowToCreateACustomControl.html

Когда вы создаете пользовательский элемент управления, скажем, CustomControl1, замените шаблон для CustomControl1 в файле Generic.xaml на этот -

<ControlTemplate TargetType="{x:Type local:CustomControl1}">
    <Border Background="{TemplateBinding Background}"
            BorderBrush="{TemplateBinding BorderBrush}"
            BorderThickness="{TemplateBinding BorderThickness}">
              <DockPanel>
                 <Button Name="btn" DockPanel.Dock="Left" ToolTip="Clear" Width="20">
                    <Image Source="pack://application:,,,/img/icons/silk/cross.png" Stretch="None" />
                </Button>
                <ComboBox Name="comboBox"
                          ItemsSource="{TemplateBinding ItemsSource}"
                          SelectedItem="{TemplateBinding SelectedItem}"
                          DisplayMemberPath="{TemplateBinding DisplayMemberPath}" />
              </DockPanel>
     </Border>
</ControlTemplate>

По умолчанию ваш класс CustomControl1 будет производным от Control. Замените его, чтобы он был производным от класса ComboBox, чтобы вам еще не приходилось объявлять DP снова, как это, и скопируйте и вставьте туда этот код -

public class CustomControl1 : ComboBox
{
        private Button clearButton;
        private ComboBox comboBox;

        static CustomControl1()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            clearButton = GetTemplateChild("btn") as Button;
            comboBox = GetTemplateChild("comboBox") as ComboBox;
            clearButton.Click += new RoutedEventHandler(clearButton_Click);
        }

        private void clearButton_Click(object sender, RoutedEventArgs e)
        {
            comboBox.SelectedItem = null;
        }
}

Теперь ваш класс CustomControl1 готов для использования в других ваших xaml-файлах, как этот -

<local:CustomControl1 ItemsSource="{Binding YourSource}"
                      SelectedItem="{Binding YourSelectedItem}"
                      Height="50" Width="200"/>
0 голосов
/ 26 октября 2011

Я думаю, что есть лучший способ, разработать упаковку / Adorner для ComboBox, которая добавляет кнопку рядом с ComboBox и стирает выделение при нажатии.

0 голосов
/ 26 октября 2011

Я решил обработать событие нажатия клавиши в поле со списком и обработать нажатие клавиши выхода, чтобы очистить поле со списком SelectedItem.

...