帶有自定義預設文字的 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();
}
}