当WPF ComboBox的选择为空时,它是否可以显示替代文本?

时间:2010-05-25 02:04:21

标签: wpf xaml combobox null

天儿真好!

我希望我的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是一种在顶部获得额外物品的方法。它是纯铬:视图模型保持纯粹和简单。只有一个问题:当ComboBox的选择为空时,用户希望显示“Select a thingo”。

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

我想避免使用带有ThingoWrapper类的ToString类污染视图模型,如果其.ActualThingo属性为null,则返回“Select a thingo”,包装每个{ {1}}填充Thingo,并找出阻止用户选择已取消Thingos的方法。

有没有办法在Thingo'边界内使用纯XAML显示“Select a thingo”,或者在视图的代码隐藏类中使用纯XAML和几行代码?

7 个答案:

答案 0 :(得分:8)

您的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外观的布局在隐藏提示文本时跳转。

答案 1 :(得分:4)

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

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

答案 2 :(得分:3)

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

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

此外,当尝试在Blend(编辑当前)中编辑控件模板时,我留下了一个无特色的组合框,没有颜色,只有一个丑陋的按钮(但是有一个无边框下拉列表)。尝试别人的建议(也许是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有一个Trigger,用于检查Property HasItems。如果为False,则在ListBox的中间显示一个说“No Items”的文本块。如果有项目,则显示它们。

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

答案 3 :(得分:3)

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

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

答案 4 :(得分:1)

我知道这是一个旧线程,但这是我如何做到的。在我获取Thingos集合之后,我只需插入一个伪造的ID值和显示值“Select a thingo”的新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是数据绑定时,第一项是“选择一个东西”。然后当选择Thingo时,我会测试SelectedThingo的ID,并相应地对其进行操作。

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

另一种选择:

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