wpf
データバインディングを使用してカスタムのUserControlを作成する
サーチ…
備考
UserControlはControlと非常に異なることに注意してください。主な違いの1つは、UserControlがXAMLレイアウトファイルを使用して、複数の個々のコントロールを配置する場所を決定することです。一方、コントロールは純粋なコードです。レイアウトファイルはまったくありません。カスタムコントロールを作成する方が、カスタムのUserControlを作成するより効果的です。
カスタムデフォルトテキストを持つComboBox
このカスタムUserControlは通常のコンボボックスとして表示されますが、組み込みのComboBoxオブジェクトとは異なり、ユーザーがまだ選択を行っていない場合は、デフォルトの文字列を表示できます。
これを達成するために、私たちのUserControlは2つのコントロールで構成されます。明らかに実際の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は、実際には2つの個別コントロールのグループです。これにより、1つのComboBoxだけでは利用できない柔軟性が実現します。
注意すべきいくつかの重要なことがあります:
- UserControl自体には
x:Name
設定されています。これは、コードビハインドにあるプロパティにバインドする必要があるためです。つまり、コードビハインドを参照する方法が必要です。 - ComboBox上の各バインディングは、
ElementName
としてUserControlの名前を持ちます。これは、UserControlがバインディングを見つけるために自分自身を見ることを知るようにするためです。 - ラベルはヒットテストでは表示されません。これは、LabelがComboBoxの一部であるという錯覚をユーザに与えるためです。
IsHitTestVisible=false
設定すると、ユーザーがラベル上にIsHitTestVisible=false
ことやラベルをクリックすることを禁止します。すべての入力は、下の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の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();
}
}