【问题标题】:Can a WPF ComboBox display alternative text when its selection is null?当 WPF 组合框的选择为空时,它可以显示替代文本吗?
【发布时间】:2010-05-25 02:04:21
【问题描述】:

生日快乐!

我希望我的 WPF ComboBox 在其数据绑定选择为 null 时显示一些替代文本。

视图模型具有预期的属性:

public ThingoSelectionViewModel : INotifyPropertyChanged {
    public ThingoSelectionViewModel(IProvideThingos) {
        this.Thingos = IProvideThingos.GetThingos();
    }

    public ObservableCollection<Thingo> Thingos { get; set; }

    public Thingo SelectedThingo { 
        get { return this.selectedThingo; }
        set { // set this.selectedThingo and raise the property change notification
    }

    // ...

}

视图以预期的方式将 XAML 绑定到视图模型:

<ComboBox x:Name="ComboboxDrive" SelectedItem="{Binding Path=SelectedThingo}"
          IsEditable="false" HorizontalAlignment="Left" MinWidth="100" 
          IsReadOnly="false" Style="{StaticResource ComboboxStyle}"
          Grid.Column="1" Grid.Row="1" Margin="5" SelectedIndex="0">
    <ComboBox.ItemsSource>
        <CompositeCollection>
        <ComboBoxItem IsEnabled="False">Select a thingo</ComboBoxItem>
        <CollectionContainer 
            Collection="{Binding Source={StaticResource Thingos}}" />
        </CompositeCollection>
    </ComboBox.ItemsSource>
</ComboBox>

楔入顶部的ComboBoxItem 是一种在顶部获得额外物品的方法。它是纯 chrome:视图模型保持纯粹和简单。只有一个问题:只要 ComboBox 的选择为空,用户就希望显示“Select a thingo”。

用户确实想要默认选择的东西。他们希望看到一条消息,告诉他们选择一个东西。

如果.ActualThingo 属性为空,我想避免使用ThingoWrapper 类和ToString 方法返回“Select a thingo”来污染视图模型,在我填充@ 时包装每个Thingo 987654330@,并想办法阻止用户选择无效的Thingo

有没有办法使用纯 XAML 或纯 XAML 以及视图的代码隐藏类中的几行代码在 ComboBox' 边界内显示“选择一个东西”?

【问题讨论】:

  • FWIW:我最终实现了 ThingoWrapper,修改了 ThingoSelectionViewModel 以应对包装的空值的选择,并找到自动选择 Whatsy 和 Fadoozamy 对象的方法,因此我不必包装它们,也。

标签: wpf xaml combobox null


【解决方案1】:

您的 MVVM 要求有多严格?可以在视图中添加一点代码隐藏吗?

也许您可以在网格中包含 ComboBox,如下所示:

<Grid>
    <ComboBox x:Name="ComboBoxControl"
              SelectionChanged="ComboBoxControl_SelectionChanged"
              HorizontalAlignment="Left" VerticalAlignment="Top" 
              MinWidth="{Binding ElementName=UnselectedText, Path=ActualWidth}">
        <ComboBoxItem>One</ComboBoxItem>
        <ComboBoxItem>Two</ComboBoxItem>
        <ComboBoxItem>Three</ComboBoxItem>
    </ComboBox>
    <TextBlock IsHitTestVisible="False" 
               x:Name="UnselectedText" 
               HorizontalAlignment="Left" 
               Text="Select an option..." 
               VerticalAlignment="Top" Margin="4" 
               Padding="0,0,30,0" />
</Grid>

然后,在代码隐藏中,在事件处理程序中插入一些逻辑:

Private Sub ComboBoxControl_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs)
    If ComboBoxControl.SelectedIndex = -1 Then
        UnselectedText.Visibility = Windows.Visibility.Visible
    Else
        UnselectedText.Visibility = Windows.Visibility.Hidden
    End If
End Sub

在 TextBlock 上设置 IsHitTestVisible="False" DependencyProperty 允许鼠标事件通过,以便您可以单击 ComboBox,并在代码隐藏中将可见性设置为 Hidden 可以防止默认 ComboBox 外观的布局在提示文字被隐藏。

【讨论】:

  • 即使你想这样做,你也不必破坏你的 MVVM。只需使用转换器将选择转换为可见性。
【解决方案2】:

您不能使用控件模板触发器,但可以为组合框设置一个简单的项目模板:

<ComboBox ItemsSource="{Binding}" >
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <TextBlock x:Name="displayText" Text="{Binding}" />
                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding}" Value="{x:Null}">
                        <Setter TargetName="displayText" Property="Text" Value="Default Value" />
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

【讨论】:

  • 嗯。我也得看看这个。
【解决方案3】:

我在这里找到的阻力最小的路径是使用 Null Object Pattern 作为在 .NET Framework 中使用此模式的示例,如果为您的 Thingo 创建 Null 对象,请考虑静态值 Double.NaN ,在您的视图模型中,您可以将其附加到列表的前面以表示“未选择任何内容”。为具有显示“选择值”的空对象实例的 DataTrigger 的 Thingo 类创建一个 DataTemplate。

我可以提供一个代码示例,但已经过了我睡觉的时间了。

【讨论】:

    【解决方案4】:

    编辑: 看起来触发的想法是行不通的。我将以下内容添加到测试组合框的控件模板中无济于事:

        <Trigger Property="SelectedItem" Value="{x:Null}">
            <Setter Property="Text" Value="No Item Selected"/>
        </Trigger>
    

    此外,当尝试在 Blend (Edit Current) 中编辑控件模板时,我留下了一个无特色的组合框,没有颜色,只有一个丑陋的按钮(但有一个无边框的下拉菜单)。试试别人的建议(也许是 Mike Brown)。

    原文:

    您可以在控制模板中使用触发器。这是一个使用我正在开发的应用程序中的 ListBox 的示例。

    <ControlTemplate x:Key="SnazzyFormListBoxTemplate" TargetType="{x:Type ListBox}">
        <Microsoft_Windows_Themes:ClassicBorderDecorator x:Name="Bd" SnapsToDevicePixels="True" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderStyle="Sunken" BorderThickness="{TemplateBinding BorderThickness}">
            <ScrollViewer Padding="{TemplateBinding Padding}" Focusable="False" Template="{DynamicResource SnazzyScrollViewerControlTemplate}">
                <Grid>
                <TextBlock x:Name="textBlock" Text="No Items" FontFamily="Arial" FontWeight="Bold" FontSize="13.333" Foreground="#4D000000" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10"/>
                <ItemsPresenter x:Name="itemsPresenter" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                </Grid>
            </ScrollViewer>
        </Microsoft_Windows_Themes:ClassicBorderDecorator>
        <ControlTemplate.Triggers>
            <Trigger Property="Selector.IsSelected" Value="True"/>
            <Trigger Property="HasItems" Value="False">
                <Setter Property="Visibility" TargetName="textBlock" Value="Visible"/>
                <Setter Property="Visibility" TargetName="itemsPresenter" Value="Collapsed"/>
            </Trigger>
            <Trigger Property="HasItems" Value="True">
                <Setter Property="Visibility" TargetName="textBlock" Value="Collapsed"/>
                <Setter Property="Visibility" TargetName="itemsPresenter" Value="Visible"/>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
    

    上面的 ControlTemplate 有一个触发器来检查属性 HasItems。如果为 False,则在 ListBox 中间显示一个“无项目”的文本块。如果有项目,就会显示出来。

    在您的情况下,更改触发器以检查 ItemSelected 是否为 x:Null 并将 Text 属性设置为“Nothing Selected”。

    【讨论】:

    • 用户询问如何在组合框中有一个“未选择”值,而不是对空的组合框有不同的外观。
    • 我知道。他们可以在控制模板中设置一个触发器,检查选定项目的状态,如果它为空,则将框文本的值设置为“未选择”。我希望用户可以从给出的示例中推断出这一点。更新了我的答案以更适合。
    • @Mike Brown:我已经编辑了我的答案,所以如果你能远程投票,我将不胜感激。
    【解决方案5】:

    我知道这是一个旧线程,但我是这样做的。获取 Thingos 集合后,我只需插入一个新的 Thingo,其 ID 值是伪造的,显示值为“Select a thingo”。

        public ThingoSelectionViewModel(IProvideThingos) {
                this.Thingos = IProvideThingos.GetThingos();
                Thingo newThingo = new Thingo();
                newThingo.ThingoID = -1;
                newThingo.ThingoDisplayName = "Select a thingo";
                this.Thingos.Insert(0, newThingo);
            }
    

    现在,当 ComboBox 被数据绑定时,第一项是“Select a thingo”。然后当一个Thingo被选中时,我会测试SelectedThingo的ID,并据此采取行动。

    【讨论】:

    • 这基本上是空对象模式。我有时会使用类的静态属性来公开 Null 对象,这样人们就可以根据 Thingo.NotSpecified 检查他们的东西。
    • Figures.... 经常有人问我是否使用或使用“某某”方法或流程,我认为答案是否定的。才发现答案是“是”,但我根本不知道它的正式名称是什么。谢谢。
    【解决方案6】:

    我知道我正在恢复一个旧帖子,但这是我在谷歌搜索中出现的第一个帖子。 在 Visual Studio 中,您可以选择将默认选择设置为 0,而不是 -1,并将您的第一个选择设置为默认文本。

    <ComboBox x:name="ThingoSelector" SelectedIndex="0">
        <ComboBoxItem IsEnabled="False">Choose Thingo</ComboBoxItem>
        <ComboBoxItem>Thingo 1</ComboBoxItem>
    </ComboBox>
    

    【讨论】:

      【解决方案7】:

      另一种选择:

      <ComboBox>
        <ComboBoxItem Visibility="Collapsed" IsSelected="True">
          <TextBlock Text="Choose item" />
        </ComboBoxItem>
        <ComboBoxItem>
          <TextBlock Text="Item 1" />
        </ComboBoxItem>
        <ComboBoxItem>
          <TextBlock Text="Item 2" />
        </ComboBoxItem>
      </ComboBox>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-10
        • 1970-01-01
        • 2015-09-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-23
        相关资源
        最近更新 更多