带有自定义默认文本的 ComboBox
此自定义 UserControl 将显示为常规组合框,但与内置 ComboBox 对象不同,它可以向用户显示默认文本字符串(如果尚未进行选择)。
为了实现这一点,我们的 UserControl 将由两个控件组成。显然我们需要一个实际的 ComboBox,但我们也会使用常规 Label 来显示默认文本。
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 就会知道自己查找绑定。 - 标签不是可见的命中测试。这是为了给用户一种错觉,即 Label 是 ComboBox 的一部分。通过设置
IsHitTestVisible=false
,我们禁止用户悬停或单击 Label - 所有输入都通过它传递到下面的 ComboBox。 - Label 使用
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,所以我们需要公开重复的属性(例如,为 ComboBox 的 ItemsSource
提供 MyItemsSource
)。然而,考虑到我们现在可以类似于本机控件使用它,这是一个小的权衡。
以下是 CustomComboBox
UserControl 的使用方法:
<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>
最终结果是:
这是 UserControl 上 Label 所需的 InverseNullVisibilityConverter,这只是 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();
}
}