WPFアプリのMVPアプリには、データベースから取得したデータを表示するコンボボックスがあります。コンボボックスにアイテムを追加する前に、次のようなデフォルトのテキストを表示したい
" - チームを選ぶ - "
そのため、ページロード時に表示され、選択時にテキストがクリアされ、アイテムが表示されます。
DBからデータを選択しています。ユーザーがコンボボックスから項目を選択するまで、デフォルトのテキストを表示する必要があります。
案内してください
私がこれを行うために見つけた最も簡単な方法は次のとおりです。
<ComboBox Name="MyComboBox"
IsEditable="True"
IsReadOnly="True"
Text="-- Select Team --" />
他のオプションを追加する必要があることは明らかですが、おそらくこれが最も簡単な方法です。
ただし、この方法には欠点が1つあります。コンボボックス内のテキストは編集できませんが、選択可能です。しかし、これまで私が見つけたすべての選択肢の質と複雑さの悪さを考えると、これはおそらく最良の選択肢です。
IValueConverter
を使用すると、コードビハインドなしでこれを実行できます。
<Grid>
<ComboBox
x:Name="comboBox1"
ItemsSource="{Binding MyItemSource}" />
<TextBlock
Visibility="{Binding SelectedItem, ElementName=comboBox1, Converter={StaticResource NullToVisibilityConverter}}"
IsHitTestVisible="False"
Text="... Select Team ..." />
</Grid>
ここには、再利用できるコンバータークラスがあります。
public class NullToVisibilityConverter : IValueConverter
{
#region Implementation of IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
最後に、リソースセクションでコンバーターを宣言する必要があります。
<Converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
Convertersは、コンバータークラスを配置した場所です。例は次のとおりです。
xmlns:Converters="clr-namespace:MyProject.Resources.Converters"
このアプローチの非常に良い点は、コードビハインドでコードが繰り返されないことです。
私はTri Qの答えが好きですが、それらの値コンバーターは使いにくいです。 PaulBはイベントハンドラーでそれを行いましたが、それも不要です。純粋なXAMLソリューションを次に示します。
<ContentControl Content="{Binding YourChoices}">
<ContentControl.ContentTemplate>
<DataTemplate>
<Grid>
<ComboBox x:Name="cb" ItemsSource="{Binding}"/>
<TextBlock x:Name="tb" Text="Select Something" IsHitTestVisible="False" Visibility="Hidden"/>
</Grid>
<DataTemplate.Triggers>
<Trigger SourceName="cb" Property="SelectedItem" Value="{x:Null}">
<Setter TargetName="tb" Property="Visibility" Value="Visible"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
純粋なxamlソリューションを複雑にしなければならないという人はいません。テキストボックスに1つのデータトリガーがある単純なものを次に示します。必要なマージンと位置
<Grid>
<ComboBox x:Name="mybox" ItemsSource="{Binding}"/>
<TextBlock Text="Select Something" IsHitTestVisible="False">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=mybox,Path=SelectedItem}" Value="{x:Null}">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
ComboBox要素にIsEditable = "True"を設定します。これにより、ComboBoxのTextプロパティが表示されます。
直接サポートされているかどうかはわかりませんが、コンボをラベルでオーバーレイし、選択範囲がnullでない場合は非表示に設定できます。
例えば。
<Grid>
<ComboBox Text="Test" Height="23" SelectionChanged="comboBox1_SelectionChanged" Name="comboBox1" VerticalAlignment="Top" ItemsSource="{Binding Source=ABCD}" />
<TextBlock IsHitTestVisible="False" Margin="10,5,0,0" Name="txtSelectTeam" Foreground="Gray" Text="Select Team ..."></TextBlock>
</Grid>
次に、選択変更ハンドラーで...
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
txtSelectTeam.Visibility = comboBox1.SelectedItem == null ? Visibility.Visible : Visibility.Hidden;
}
IceForgeの答え に基づいて、再利用可能なソリューションを準備しました。
xamlスタイル:
<Style x:Key="ComboBoxSelectOverlay" TargetType="TextBlock">
<Setter Property="Grid.ZIndex" Value="10"/>
<Setter Property="Foreground" Value="{x:Static SystemColors.GrayTextBrush}"/>
<Setter Property="Margin" Value="6,4,10,0"/>
<Setter Property="IsHitTestVisible" Value="False"/>
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding}" Value="{x:Null}">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
使用例:
<Grid>
<ComboBox x:Name="cmb"
ItemsSource="{Binding Teams}"
SelectedItem="{Binding SelectedTeam}"/>
<TextBlock DataContext="{Binding ElementName=cmb,Path=SelectedItem}"
Text=" -- Select Team --"
Style="{StaticResource ComboBoxSelectOverlay}"/>
</Grid>
HappyNomadのソリューションは非常に優れており、最終的にこのわずかに異なるソリューションに到達するのに役立ちました。
<ComboBox x:Name="ComboBoxUploadProject"
Grid.Row="2"
Width="200"
Height="23"
Margin="64,0,0,0"
ItemsSource="{Binding projectList}"
SelectedValue ="{Binding projectSelect}"
DisplayMemberPath="projectName"
SelectedValuePath="projectId"
>
<ComboBox.Template>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ComboBox x:Name="cb"
DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}"
ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource TemplatedParent}}"
SelectedValue ="{Binding SelectedValue, RelativeSource={RelativeSource TemplatedParent}}"
DisplayMemberPath="projectName"
SelectedValuePath="projectId"
/>
<TextBlock x:Name="tb" Text="Select Item..." Margin="3,3,0,0" IsHitTestVisible="False" Visibility="Hidden"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger SourceName="cb" Property="SelectedItem" Value="{x:Null}">
<Setter TargetName="tb" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ComboBox.Template>
</ComboBox>
最も簡単な方法は、CompositeCollectionを使用して、データベースのデフォルトのテキストとデータをComboBoxで直接マージすることです。
<ComboBox x:Name="SelectTeamComboBox" SelectedIndex="0">
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem Visibility="Collapsed">-- Select Team --</ComboBoxItem>
<CollectionContainer Collection="{Binding Source={StaticResource ResourceKey=MyComboOptions}}"/>
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
また、ResourcesでStaticResourceを定義して、ComboBoxオプションをDataContextにバインドします。これは、CollectionContainerの直接バインドが正しく機能しないためです。
<Window.Resources>
<CollectionViewSource Source="{Binding}" x:Key="MyComboOptions" />
</Window.Resources>
この方法では、xamlでのみComboBoxオプションを定義できます。
<ComboBox x:Name="SelectTeamComboBox" SelectedIndex="0">
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem Visibility="Collapsed">-- Select Team --</ComboBoxItem>
<ComboBoxItem >Option 1</ComboBoxItem>
<ComboBoxItem >Option 2</ComboBoxItem>
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
IceForgeの答え はかなり近く、この問題に対する最も簡単な解決策です。しかし、機能していなかったため、何かを見逃していました(少なくとも私にとっては、実際にテキストを表示することはありません)。
最終的に、TextBlockの「Visibility」プロパティを「Hidden」に設定するだけでは、コンボボックスの選択項目がnullでない場合に非表示にできません。デフォルトでそのように設定する必要があります(トリガーと同じ場所でXAMLのセッターを使用して、 トリガーでnull以外をチェックできない であるため)。
トリガーの直前に配置されている欠落しているセッターに基づいた実際のソリューションは次のとおりです。
<ComboBox x:Name="combo"/>
<TextBlock Text="--Select Team--" IsHitTestVisible="False">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Setters>
<Setter Property="Visibility" Value="Hidden"/>
</Style.Setters>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=combo,Path=SelectedItem}" Value="{x:Null}">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
以下をお勧めします。
動作を定義する
public static class ComboBoxBehaviors
{
public static readonly DependencyProperty DefaultTextProperty =
DependencyProperty.RegisterAttached("DefaultText", typeof(String), typeof(ComboBox), new PropertyMetadata(null));
public static String GetDefaultText(DependencyObject obj)
{
return (String)obj.GetValue(DefaultTextProperty);
}
public static void SetDefaultText(DependencyObject obj, String value)
{
var combo = (ComboBox)obj;
RefreshDefaultText(combo, value);
combo.SelectionChanged += (sender, _) => RefreshDefaultText((ComboBox)sender, GetDefaultText((ComboBox)sender));
obj.SetValue(DefaultTextProperty, value);
}
static void RefreshDefaultText(ComboBox combo, string text)
{
// if item is selected and DefaultText is set
if (combo.SelectedIndex == -1 && !String.IsNullOrEmpty(text))
{
// Show DefaultText
var visual = new TextBlock()
{
FontStyle = FontStyles.Italic,
Text = text,
Foreground = Brushes.Gray
};
combo.Background = new VisualBrush(visual)
{
Stretch = Stretch.None,
AlignmentX = AlignmentX.Left,
AlignmentY = AlignmentY.Center,
Transform = new TranslateTransform(3, 0)
};
}
else
{
// Hide DefaultText
combo.Background = null;
}
}
}
ユーザーの動作
<ComboBox Name="cmb" Margin="72,121,0,0" VerticalAlignment="Top"
local:ComboBoxBehaviors.DefaultText="-- Select Team --"/>
編集:以下のコメントごとに、これは解決策ではありません。私はそれがどのように機能していたのか分かりませんが、そのプロジェクトを確認することはできません。
この答えを最新のXAMLに更新する時が来ました。
このSO質問を見つけて、この質問の解決策を探して、更新されたXAML仕様には簡単な解決策があることがわかりました。
このタスクを実行するために、「プレースホルダー」という属性が使用可能になりました。これは簡単です(Visual Studio 2015):
<ComboBox x:Name="Selection" PlaceholderText="Select...">
<x:String>Item 1</x:String>
<x:String>Item 2</x:String>
<x:String>Item 3</x:String>
</ComboBox>
このようにコードビハインドでデータベースからのデータをコンボボックスにバインドする前にそれを行いました-
Combobox.Items.Add("-- Select Team --");
Combobox.SelectedIndex = 0;
少し遅れましたが.
より簡単な方法は、パラメーターIsDummy = trueでダミーデータ項目をリストに追加し、それがHitTestVisableでなく、高さが1ピクセル(コンバーターを使用)であることを確認して、それが表示されないようにすることです。
SelectionChangedに登録するだけでなく、その中でインデックスをダミーのアイテムインデックスに設定します。
これは魅力のように機能し、この方法でComboBoxまたはアプリケーションテーマのスタイルと色を混乱させません。
解決
1。コンボボックスの上にラベルを貼ります。
2。ラベルのコンテンツをコンボボックスのTextプロパティにバインドします。
3。コンボボックスの不透明度をゼロ、Opacity = 0に設定します。
4。コンボボックスのTextプロパティにデフォルトのテキストを書き込む
<Grid>
<Label Content="{Binding ElementName=cb, Path=Text}"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
Height="{Binding ElementName=cb, Path=Height}"
Width="{Binding ElementName=cb, Path=Width}"/>
<ComboBox Name="cb"
Text="--Select Team--" Opacity="0"
Height="40" Width="140" >
<ComboBoxItem Content="Manchester United" />
<ComboBoxItem Content="Lester" />
</ComboBox>
</Grid>
私はプロジェクトでIsNullConverterクラスを使用していますが、うまくいきました。使用されているトリガーはnullではなく値をサポートしていないため、C#でのコードはConverterという名前のフォルダを作成し、そのフォルダにこのクラスを追加します.IsNullConverterはそれを行います
public class IsNullConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value == null);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException("IsNullConverter can only be used OneWay.");
}
}
このようなxamlファイルに名前空間を追加します。
xmlns:Converters="clr-namespace:TymeSheet.Converter"
手段
xmlns:Converters="clr-namespace:YourProjectName.Converter"
リソースの下にあるこの行を使用して、xamlコードで使用できるようにします
<Converters:IsNullConverter x:Key="isNullConverter" />
これがxamlコードです。ここではトリガーを使用しているため、コンボボックスでアイテムが選択されるたびに、テキストの可視性が偽になります。
<TextBlock Text="Select Project" IsHitTestVisible="False" FontFamily="/TimeSheet;component/Resources/#Open Sans" FontSize="14" Canvas.Right="191" Canvas.Top="22">
<TextBlock.Resources>
<Converters:IsNullConverter x:Key="isNullConverter"/>
</TextBlock.Resources>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ProjectComboBox,Path=SelectedItem,Converter={StaticResource isNullConverter}}" Value="False">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
// XAMLコード
// ViewModelコード
private CategoryModel _SelectedCategory;
public CategoryModel SelectedCategory
{
get { return _SelectedCategory; }
set
{
_SelectedCategory = value;
OnPropertyChanged("SelectedCategory");
}
}
private ObservableCollection<CategoryModel> _Categories;
public ObservableCollection<CategoryModel> Categories
{
get { return _Categories; }
set
{
_Categories = value;
_Categories.Insert(0, new CategoryModel()
{
CategoryId = 0,
CategoryName = " -- Select Category -- "
});
SelectedCategory = _Categories[0];
OnPropertyChanged("Categories");
}
}
InitializeComponent()
yourcombobox.text=" -- Select Team --";
上記のコードは、最も簡単な方法を示しています。ウィンドウのロード後、コンボボックスの.Textプロパティを使用して、コンボボックスのテキストを宣言します。これは、DatePicker、Textbox、およびその他のコントロールにも拡張できます。
ベストプラクティスではありませんが、正常に動作します...
<ComboBox GotFocus="Focused" x:Name="combobox1" HorizontalAlignment="Left" Margin="8,29,0,0" VerticalAlignment="Top" Width="128" Height="117"/>
コードビハインド
public partial class MainWindow : Window
{
bool clearonce = true;
bool fillonce = true;
public MainWindow()
{
this.InitializeComponent();
combobox1.Items.Insert(0, " -- Select Team --");
combobox1.SelectedIndex = 0;
}
private void Focused(object sender, RoutedEventArgs e)
{
if(clearonce)
{
combobox1.Items.Clear();
clearonce = false;
}
if (fillonce)
{
//fill the combobox items here
for (int i = 0; i < 10; i++)
{
combobox1.Items.Insert(i, i);
}
fillonce = false;
}
}
}
言及されている透かし この投稿で はこの場合うまくいくと思います
少しコードが必要ですが、任意のコンボボックスまたはテキストボックス(さらにはパスワードボックス)に再利用できるので、この方法が好きです