当 WPF ComboBox 的选择为空时,它可以显示替代文本吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2901536/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can a WPF ComboBox display alternative text when its selection is null?
提问by Garth Kidd
G'day!
日!
I want my WPF ComboBox
to display some alternative text when its data-bound selection is null
.
我希望我的 WPFComboBox
在其数据绑定选择为null
.
The view model has the expected properties:
视图模型具有预期的属性:
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
}
// ...
}
The view has XAML binding to the view model in the expected way:
视图以预期的方式将 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>
The ComboBoxItem
wedged into the top is a way to get an extra item at the top. It's pure chrome: the view model stays pure and simple. There's just one problem: the users want "Select a thingo" displayed whenever the ComboBox' selection is null.
该ComboBoxItem
楔入顶部的方式在顶部得到一个额外的项目。它是纯 chrome:视图模型保持纯粹和简单。只有一个问题:用户希望在 ComboBox 的选择为空时显示“选择一个事物”。
The users do notwant a thingo selected by default. They want to see a message telling them to select a thingo.
用户不希望默认选择某个事物。他们希望看到一条消息,告诉他们选择一个事物。
I'd like to avoid having to pollute the viewmodel with a ThingoWrapper
class with a ToString
method returning "Select a thingo" if its .ActualThingo
property is null, wrapping each Thingo
as I populate Thingos
, and figuring out some way to prevent the user from selecting the nulled Thingo
.
我想避免使用一个ThingoWrapper
类来污染视图模型,ToString
如果它的.ActualThingo
属性为空,则返回“Select a thingo”的方法,Thingo
在我填充时包装每个Thingos
,并找出某种方法来防止用户选择 nulled Thingo
。
Is there a way to display "Select a thingo" within the ComboBox
' boundaries using pure XAML, or pure XAML and a few lines of code in the view's code-behind class?
有没有办法ComboBox
使用纯 XAML 或纯 XAML 和视图的代码隐藏类中的几行代码在 ' 边界内显示“选择事物” ?
采纳答案by Michael Brown
The path of least resistance here that I've found is to use the Null Object PatternFor an example of using this pattern in the .NET Framework, consider the static value Double.NaN if you create a Null Object for your Thingo, in your view model you can append it to the front of your list to signify "nothing is selected". Create a DataTemplate for the Thingo class that has a DataTrigger for the Null Object instance that shows "Select a Value".
我在这里找到的阻力最小的路径是使用Null Object Pattern作为在 .NET Framework 中使用此模式的示例,如果您为 Thingo 创建 Null Object,请考虑静态值 Double.NaN,在您的视图模型,您可以将其附加到列表的前面以表示“没有选择任何内容”。为 Thingo 类创建一个 DataTemplate,该类具有用于显示“选择值”的 Null 对象实例的 DataTrigger。
I could give a code sample but it's past my bed time.
我可以提供一个代码示例,但它已经过了我的睡觉时间。
回答by Rob Perkins
How strict is your MVVM requirement? Can you have a little code-behind in the view?
您的 MVVM 要求有多严格?你能在视图中隐藏一些代码吗?
Perhaps you could contain the ComboBox in a grid, something like this:
也许您可以在网格中包含 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>
Then, in the code-behind, insert some logic in an event handler:
然后,在代码隐藏中,在事件处理程序中插入一些逻辑:
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
Setting the IsHitTestVisible="False"
DependencyProperty on the TextBlock lets mouse events through so that you can click on the ComboBox, and setting the visibility to Hidden
in the code-behind keeps the layout of a default ComboBox's appearance from jumping around when the prompt text is hidden.
IsHitTestVisible="False"
在 TextBlock 上设置DependencyProperty 允许鼠标事件通过,以便您可以单击 ComboBox,并Hidden
在代码隐藏中将可见性设置为保持默认 ComboBox 外观的布局不会在提示文本隐藏时跳来跳去。
回答by Steve Greatrex
You can't use a control template trigger, but you could set up a simple item template for the combobox:
您不能使用控件模板触发器,但可以为组合框设置一个简单的项目模板:
<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>
回答by CodeWarrior
Edit:Looks like the trigger idea is a no go. I added the following to the control template of a test combo box to no avail:
编辑:看起来触发的想法是不行的。我在测试组合框的控件模板中添加了以下内容,但无济于事:
<Trigger Property="SelectedItem" Value="{x:Null}">
<Setter Property="Text" Value="No Item Selected"/>
</Trigger>
Additionally, when trying to edit the control template in Blend (Edit Current) I am left with a featureless combobox, no colors, just an ugly button (but there is a borderless dropdown). Try someone elses suggestion (Mike Brown perhaps).
此外,当尝试在 Blend (Edit Current) 中编辑控件模板时,我只剩下一个无特色的组合框,没有颜色,只有一个丑陋的按钮(但有一个无边框下拉菜单)。尝试别人的建议(也许是迈克布朗)。
Original:
原来的:
You can use a Trigger in the Control template. Here is an example using a ListBox from an app I am working on.
您可以在控制模板中使用触发器。这是一个使用我正在开发的应用程序中的 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>
The above ControlTemplate has a Trigger which checks the Property HasItems. If False, a textblock saying "No Items" is displayed in the middle of the ListBox. If there are Items, they are displayed.
上面的 ControlTemplate 有一个触发器来检查属性 HasItems。如果为 False,则在 ListBox 中间显示一个文本块,上面写着“No Items”。如果有项目,则显示它们。
In your case change the trigger to check to see if ItemSelected is x:Null and set the Text property to "Nothing Selected".
在您的情况下,更改触发器以检查 ItemSelected 是否为 x:Null 并将 Text 属性设置为“Nothing Selected”。
回答by D'Hag
I know this is an old thread, but here is how I do it. After I fetch the Thingos collection, I simply insert a new Thingo with a bogus ID value and a display value of "Select a thingo."
我知道这是一个旧线程,但这是我的方法。在我获取 Thingos 集合后,我只需插入一个带有虚假 ID 值和“选择一个事物”的显示值的新 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);
}
Now, when the ComboBox is databound, the first item is "Select a thingo." Then when a Thingo is selected, I test the ID of the SelectedThingo, and act on it accordingly.
现在,当 ComboBox 是数据绑定的时,第一项是“选择一个事物”。然后选择何时选择Thingo,我测试SelectsThepo的ID,并相应地采用它。
回答by Hyren
I know I'm resurrecting an old post, but this was the first one that came up on my google search. In Visual Studio, you can choose to set the Default Selection to 0, instead of -1, and just have your first selection be the default text.
我知道我正在复活一个旧帖子,但这是我在谷歌搜索中出现的第一个帖子。在 Visual Studio 中,您可以选择将默认选择设置为 0,而不是 -1,并将您的第一个选择设置为默认文本。
<ComboBox x:name="ThingoSelector" SelectedIndex="0">
<ComboBoxItem IsEnabled="False">Choose Thingo</ComboBoxItem>
<ComboBoxItem>Thingo 1</ComboBoxItem>
</ComboBox>
回答by user9198839
Another option:
另外一个选项:
<ComboBox>
<ComboBoxItem Visibility="Collapsed" IsSelected="True">
<TextBlock Text="Choose item" />
</ComboBoxItem>
<ComboBoxItem>
<TextBlock Text="Item 1" />
</ComboBoxItem>
<ComboBoxItem>
<TextBlock Text="Item 2" />
</ComboBoxItem>
</ComboBox>