天儿真好!
我希望我的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和几行代码?
答案 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>