WPF 앱의 MVP 앱에는 데이터베이스에서 가져온 데이터를 표시하는 콤보 상자가 있습니다. 콤보 상자에 항목을 추가하기 전에 다음과 같은 기본 텍스트를 표시하고 싶습니다.
"-팀 선택-"
페이지로드시 표시되고 선택시 텍스트가 지워지고 항목이 표시되도록합니다.
DB에서 데이터를 선택하고 있습니다. 사용자가 콤보 상자에서 항목을 선택할 때까지 기본 텍스트를 표시해야합니다.
나를 안내 해주세요
WPF 앱의 MVP 앱에는 데이터베이스에서 가져온 데이터를 표시하는 콤보 상자가 있습니다. 콤보 상자에 항목을 추가하기 전에 다음과 같은 기본 텍스트를 표시하고 싶습니다.
"-팀 선택-"
페이지로드시 표시되고 선택시 텍스트가 지워지고 항목이 표시되도록합니다.
DB에서 데이터를 선택하고 있습니다. 사용자가 콤보 상자에서 항목을 선택할 때까지 기본 텍스트를 표시해야합니다.
나를 안내 해주세요
답변:
이 작업을 수행하는 가장 쉬운 방법은 다음과 같습니다.
<ComboBox Name="MyComboBox"
IsEditable="True"
IsReadOnly="True"
Text="-- Select Team --" />
분명히 다른 옵션을 추가해야하지만 이것이 아마도 가장 간단한 방법 일 것입니다.
그러나이 방법에는 한 가지 단점이 있습니다. 콤보 상자 내부의 텍스트는 편집 할 수 없지만 여전히 선택할 수 있다는 것입니다. 그러나 지금까지 찾은 모든 대안의 품질과 복잡성이 낮기 때문에 이것이 아마도 최고의 옵션 일 것입니다.
Focusable="False" IsEditable="True" IsReadOnly="True"
.NET Framework를 사용하여 코드 뒤에 코드없이이 작업을 수행 할 수 있습니다 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"
이 접근 방식의 가장 좋은 점은 코드 뒤에서 코드를 반복하지 않는다는 것입니다.
DataTrigger
여기에서 변환기 코드조차 피하기 위해 a 를 사용할 수 있습니다. :)
나는 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>
<Setter Property="Visibility" Value="Hidden"/>
방아쇠 외부 (스타일 내부)를 추가 Visibility="Hidden"
하고 실제 텍스트 블록 요소에서 제거하는 것을 의미한다고 생각한다
요소 IsEditable="True"
에 설정 합니다 ComboBox
. 이것은의 Text
속성을 표시 합니다 ComboBox
.
직접 지원되는지는 모르겠지만 콤보를 레이블로 오버레이하고 선택이 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를 정의하여 CollectionContainer의 직접 바인딩이 올바르게 작동하지 않기 때문에 ComboBox 옵션을 DataContext에 바인딩합니다.
<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>
다음을 권장합니다.
행동 정의
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 --"/>
IceForge의 답변 은 매우 가깝고 AFAIK가이 문제에 대한 가장 쉬운 해결책입니다. 그러나 작동하지 않아서 무언가를 놓쳤습니다 (적어도 저에게는 실제로 텍스트를 표시하지 않습니다).
결국 콤보 상자의 선택한 항목이 null이 아닐 때 숨겨 지도록 TextBlock의 "Visibility"속성을 "Hidden"으로 설정할 수 없습니다. 기본적으로 그렇게 설정해야합니다 ( 트리거에서 null이 아닌지 확인할 수 없기 때문에 와 동일한 위치에서 XAML의 Setter를 사용하여 에서 .
다음은 트리거 바로 앞에 놓인 누락 된 Setter를 기반으로 한 실제 솔루션입니다.
<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>
편집 : 아래 의견에 따라 이것은 해결책이 아닙니다. 내가 어떻게 작동했는지 확실하지 않으며 해당 프로젝트를 확인할 수 없습니다.
최신 XAML에 대한이 답변을 업데이트 할 때입니다.
이 질문에 대한 해결책을 찾기 위해이 질문을 찾은 다음 업데이트 된 XAML 사양에 간단한 해결책이 있음을 발견했습니다.
이제 "Placeholder"라는 속성을 사용하여이 작업을 수행 할 수 있습니다. 다음과 같이 간단합니다 (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>
PlaceholderText
, System.Windows.ComboBox
클래스에 재산 이 없기 때문에 투표를 받았다고 생각합니다 . 이것은 WinForms가 아니라 WPF에 대한 질문입니다.
모범 사례는 아니지만 잘 작동합니다 ...
<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;
}
}
}
이 게시물에서 언급 한 워터 마크 가이 경우에 잘 작동 할 것이라고 생각합니다.
약간의 코드가 필요하지만 모든 콤보 상자 또는 텍스트 상자 (심지어 암호 상자)에 다시 사용할 수 있으므로이 방법을 선호합니다.
내 프로젝트에서 IsNullConverter 클래스를 사용하고 있는데 저에게 효과적이었습니다. 여기에 C #의 코드가 있습니다. Converter라는 폴더를 만들고 해당 폴더에이 클래스를 추가합니다. 사용 된 트리거가 null이 아닌 값을 지원하지 않으므로 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");
}
}
다음과 같이 코드 숨김에서 데이터베이스의 데이터로 콤보 상자를 바인딩하기 전에 수행했습니다.
Combobox.Items.Add("-- Select Team --");
Combobox.SelectedIndex = 0;
콤보 박스 위에 라벨을 붙입니다.
레이블의 내용을 콤보 상자 Text 속성에 바인딩합니다.
콤보 박스의 불투명도를 0, Opacity = 0으로 설정합니다.
콤보 상자 Text 속성에 기본 텍스트 쓰기
<ComboBox Name="cb"
Text="--Select Team--" Opacity="0"
Height="40" Width="140" >
<ComboBoxItem Content="Manchester United" />
<ComboBoxItem Content="Lester" />
</ComboBox>
</Grid>
나는 이것이 반쯤 된 것을 알고 있지만 이런 식으로 어떨까요?
<DataTemplate x:Key="italComboWM">
<TextBlock FontSize="11" FontFamily="Segoe UI" FontStyle="Italic" Text="--Select an item--" />
</DataTemplate>
<ComboBox EmptySelectionBoxTemplate="{StaticResource italComboWM}" />
ComboBox
EmptySelectionBoxTemplate
재산 이 없습니다 .