#c# #wpf #user-controls #combobox #dependency-properties
#c# #wpf #пользовательские элементы управления #выпадающий список #свойства зависимостей
Вопрос:
Перед ComboBox
тем, как будет выбран какой-либо элемент в a, его SelectedItem
значение равно null, а ComboBox
сам элемент визуально пуст. Как только что-то выбрано, у пользователя, похоже, нет никакого способа выбрать «отсутствие выделения» (хотя это можно сделать, установив значение SelectedItem
null в коде).
Мои выпадающие списки привязаны к наблюдаемым коллекциям моих объектов. Я не хочу добавлять «специальный» первый нулевой объект в начало каждой ObservableCollection. Итак, я пользуюсь этой возможностью, чтобы немного узнать о написании UserControl.
Проблема SelectedItem
в том, что он работает не так, как обычно. То есть объект ComboBox
хорошо привязан к резервной ObservableCollection
копии, но выбор чего-либо из ComboBox
не обновляет SelectedItem
то, к чему он должен быть привязан.
Я чувствую, что мне нужно передавать некоторую информацию из ComboBox в UserControl … куда-нибудь. Я на правильном пути? Что я должен искать в Google?
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 :(
Ответ №1:
Поскольку combobox является производным от Selector
class, который, в свою очередь, является производным от ItemsControl
. Итак, извлекая из UserControl, вы лишаете свой combobox свойств класса Selector, которые могут внутренне обрабатывать объект выбора для вас. итак, я бы предложил вместо того, чтобы выводить его из UserControl, вы должны вывести его из Combobox следующим образом —
public partial class ClearableComboBox : ComboBox
Таким образом, вам не придется переопределять ItemsSource
, DisplayMemberPath и т. Д. в вашем классе, поскольку он уже присутствует в ComboBox
классе. Вы всегда можете расширить свой класс дальше, чтобы предоставить дополнительные функции, которые в вашем случае устанавливают значение SelectedItem
null при нажатии какой-либо кнопки. Надеюсь, это то, что вы хотите..
РЕДАКТИРОВАТЬ (пользовательский элемент управления)
Создание пользовательского элемента управления — это ваш ответ здесь, чтобы начать, если вы не знаете об этом, посмотрите на это для начала — 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
. Замените его на производный от class 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"/>
Комментарии:
1. Как бы вы посоветовали мне очистить мой ClearableComboBox с помощью щелчка мыши?
2. Я обновил свой ответ с использованием пользовательского элемента управления. Посмотрите и дайте мне знать в случае каких-либо проблем.
3. Когда я использую
<local:CustomControl1 ItemsSource="{Binding Foo}" SelectedItem="{Binding SelectedFoo, Mode=TwoWay}" />
, он заполняется Foos, но SelectedFoo не обновляется, когда я выбираю Foo из выпадающего списка.4. Пришлось использовать следующее:
SelectedItem="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedItem}"
Ответ №2:
Я решил обработать событие нажатия клавиши в поле со списком и обработать нажатие клавиши escape, чтобы очистить поле со списком SelectedItem
.
Комментарии:
1. Поле со списком находится в окне, которое было показано с помощью ShowDialog() , поэтому клавиша escape закроет окно вместо очистки поля со списком.
Ответ №3:
Я думаю, что есть лучший способ, разработать оболочку / украшение для ComboBox
, которая добавляет кнопку рядом с ComboBox
и стирает выделение по щелчку.
Комментарии:
1. Да, это не помогло. Я считаю, что IsSynchronizedWithCurrentItem имеет больше общего с базовым CollectionView (или CollectionViewSource?).