wpf
Создание пользовательских UserControls с привязкой данных
Поиск…
замечания
Обратите внимание, что UserControl сильно отличается от элемента управления. Одно из основных отличий заключается в том, что UserControl использует файл макета XAML для определения места размещения нескольких отдельных элементов управления. A Control, с другой стороны, является просто чистым кодом - нет файла макета вообще. В некотором смысле создание настраиваемого элемента управления может быть более эффективным, чем создание пользовательского UserControl.
ComboBox с настраиваемым текстом по умолчанию
Этот пользовательский UserControl появится как обычный combobox, но в отличие от встроенного объекта ComboBox он может показать пользователю строку текста по умолчанию, если они еще не сделали выбор.
Для этого наш UserControl будет состоять из двух элементов управления. Очевидно, нам нужен фактический ComboBox, но мы также будем использовать обычный ярлык для отображения текста по умолчанию.
CustomComboBox.xaml
<UserControl x:Class="UserControlDemo.CustomComboBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cnvrt="clr-namespace:UserControlDemo"
x:Name="customComboBox">
<UserControl.Resources>
<cnvrt:InverseNullVisibilityConverter x:Key="invNullVisibleConverter" />
</UserControl.Resources>
<Grid>
<ComboBox x:Name="comboBox"
ItemsSource="{Binding ElementName=customComboBox, Path=MyItemsSource}"
SelectedItem="{Binding ElementName=customComboBox, Path=MySelectedItem}"
HorizontalContentAlignment="Left" VerticalContentAlignment="Center"/>
<Label HorizontalAlignment="Left" VerticalAlignment="Center"
Margin="0,2,20,2" IsHitTestVisible="False"
Content="{Binding ElementName=customComboBox, Path=DefaultText}"
Visibility="{Binding ElementName=comboBox, Path=SelectedItem, Converter={StaticResource invNullVisibleConverter}}"/>
</Grid>
</UserControl>
Как вы можете видеть, этот единственный UserControl фактически представляет собой группу из двух отдельных элементов управления. Это дает нам некоторую гибкость, которая недоступна только в одном ComboBox.
Вот несколько важных замечаний:
- Сам UserControl имеет набор
x:Name
. Это связано с тем, что мы хотим привязываться к свойствам, которые находятся в коде, что означает, что ему нужен какой-то способ ссылаться на себя. - Каждое из связываний в ComboBox имеет имя UserControl как
ElementName
. Это значит, что UserControl знает, как искать привязки. - Ярлык не является видимым. Это должно дать пользователю иллюзию, что ярлык является частью ComboBox. Установив
IsHitTestVisible=false
, мы запрещаем пользователюIsHitTestVisible=false
на Label - все данные передаются через ComboBox ниже. - Ярлык использует конвертер
InverseNullVisibility
для определения того, должен ли он отображаться сам или нет. Вы можете найти код для этого в нижней части этого примера.
CustomComboBox.xaml.cs
public partial class CustomComboBox : UserControl
{
public CustomComboBox()
{
InitializeComponent();
}
public static DependencyProperty DefaultTextProperty =
DependencyProperty.Register("DefaultText", typeof(string), typeof(CustomComboBox));
public static DependencyProperty MyItemsSourceProperty =
DependencyProperty.Register("MyItemsSource", typeof(IEnumerable), typeof(CustomComboBox));
public static DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(object), typeof(CustomComboBox));
public string DefaultText
{
get { return (string)GetValue(DefaultTextProperty); }
set { SetValue(DefaultTextProperty, value); }
}
public IEnumerable MyItemsSource
{
get { return (IEnumerable)GetValue(MyItemsSourceProperty); }
set { SetValue(MyItemsSourceProperty, value); }
}
public object MySelectedItem
{
get { return GetValue(MySelectedItemProperty); }
set { SetValue(MySelectedItemProperty, value); }
}
}
В коде, мы просто раскрываем, какие свойства мы хотим быть доступными программисту, используя этот UserControl. К сожалению, поскольку у нас нет прямого доступа к ComboBox извне этого класса, нам нужно выставить повторяющиеся свойства (например, MyItemsSource
для ComboBox's ItemsSource
). Тем не менее, это незначительный компромисс, учитывая, что теперь мы можем использовать его аналогично собственному контролю.
Вот как можно использовать UserControl CustomComboBox
:
<Window x:Class="UserControlDemo.UserControlDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cntrls="clr-namespace:UserControlDemo"
Title="UserControlDemo" Height="240" Width=200>
<Grid>
<cntrls:CustomComboBox HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="165"
MyItemsSource="{Binding Options}"
MySelectedItem="{Binding SelectedOption, Mode=TwoWay}"
DefaultText="Select an option..."/>
<Grid>
</Window>
И конечный результат:
Вот InverseNullVisibilityConverter, необходимый для Label на UserControl, который является лишь небольшим изменением версии lll :
public class InverseNullVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? Visibility.Visible : Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}