combobox combobox - 如何在WPF頁面加載的組合框中顯示默認文本“ - 選擇團隊 - ”?





item binding (19)


沒有用組合框試過它,但這對我來說已經適用於其他控件...

ageektrapped blogpost

他在這裡使用裝飾層來顯示水印。

在WPF應用程序中,在MVP應用程序中,我有一個組合框,為此我顯示從數據庫獲取的數據。 在項目添加到組合框之前,我想顯示默認文本,如

“ - 選擇團隊 - ”

以便在頁面加載時顯示並選擇它,文本應該被清除並且應該顯示項目。

正在從數據庫中選擇數據。 我需要顯示默認文本,直到用戶從組合框中選擇一個項目。

請指導我




您可以通過使用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" />

轉換器是您放置轉換器類的地方。 一個例子是:

xmlns:Converters="clr-namespace:MyProject.Resources.Converters"

這種方法的好處是不會在代碼背後重複代碼。




我會建議如下:

定義一個行為

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 --"/>



在Combobox元素上設置IsEditable = True。 這將顯示Combobox的Text屬性




我在將代碼隱藏數據庫中的數據綁定到組合框之前做到了這一點 -

Combobox.Items.Add("-- Select Team --");
Combobox.SelectedIndex = 0;



編輯:下面的評論,這不是一個解決方案。 不知道我是如何工作的,無法檢查該項目。

現在是更新最新XAML的答案的時候了。

找到這個問題尋找這個問題的解決方案,然後我發現更新的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>



基於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>



我不知道它是否直接支持,但你可以覆蓋組合標籤,並將其設置為隱藏,如果選擇不為空。

例如。

<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的答案非常接近,並且AFAIK是解決這個問題的最簡單的解決方案。 但它錯過了一些東西,因為它不起作用(至少對我而言,它從未實際顯示文本)。

最後,當組合框的選定項不為空時,您不能只將TextBlock的“可見性”屬性設置為“隱藏”,以便隱藏它; 你必須默認設置它(因為你不能在觸發器中使用XAML中的Setter來檢查觸發器中是否為null) 。

以下是基於他的實際解決方案,缺少的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>



InitializeComponent()
yourcombobox.text=" -- Select Team --";

上面的代碼演示了實現它的最簡單方法。 窗口加載後,使用組合框的.Text屬性聲明組合框的文本。 這可以擴展到DatePicker,Textbox和其他控件。




只能將IsEditable屬性設置為true

<ComboBox Name="comboBox1"            
          Text="--Select Team--"
          IsEditable="true"  <---- that's all!
          IsReadOnly="true"/>



沒有人說純粹的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>



我在我的項目中使用了IsNullConverter類,它對我很有用。 這裡是它在c#中的代碼,創建一個名為Converter的文件夾並將該類添加到該文件夾中,因為所使用的觸發器不支持value而不是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>



我喜歡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>



有點晚了,但..

更簡單的方法是用參數IsDummy = true向列表中添加一個虛擬數據項,並確保它不是HitTestVisable,其高度為1像素(使用Converter),因此不會被看到。

除了註冊到SelectionChanged並在其中,將索引設置為虛擬物品索引。

它就像一個魅力,這樣你就不會混淆組合框或應用程序主題的風格和顏色。




我相信這篇文章中提到的水印在這種情況下可以很好地工作

有一些需要的代碼,但你可以重複使用它的任何組合框或文本框(甚至密碼箱),所以我更喜歡這種方式




// 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");

        }
    }



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>



在分配ValueMemberDatamember屬性後,請務必在onload()函數中設置DataSource屬性。

這將幫助您解決問題!





wpf combobox