c# - 组合框项目源 = ObservableCollection & 我需要在顶部有一个 '-None-' 虚拟条目

标签 c# wpf combobox observablecollection itemsource

我有一个使用可观察集合作为数据源的组合框,我希望“无”的“虚拟”值作为框中的第一项,因为它控制针对其他数据源的过滤器。

其他数据绑定(bind)对象也使用相同的可观察集合,因此无法直接向数据源添加“无”值,因为我不想这样做,例如,我的数据网格中有一个“无”。 此外,我宁愿避免过滤器只为那些不使用它的人删除“无”值,因为我希望可观察集合直接反射(reflect)数据库数据;如果可能的话。 我还想避免每个数据绑定(bind)控件有一个可观察集合。

我真正想要的是将一个非数据绑定(bind)的第一个条目放入组合框,同时让项目源指向一个可观察的集合。

谢谢

/编辑:我现在正在使用 XAML,但是当单击虚拟第一项时它不会关闭组合框

<ComboBox x:Class="TestManager.Controls.NullableComboBox"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:w="clr-namespace:System.Windows.Controls;assembly=PresentationFramework"
         xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300" MouseUp="ComboBox_MouseUp">
<ComboBox.Resources>
    <Geometry x:Key="DownArrowGeometry">M 0 0 L 3.5 4 L 7 0 Z</Geometry>
    <Style x:Key="ComboBoxReadonlyToggleButton" TargetType="{x:Type ToggleButton}">
        <Setter Property="OverridesDefaultStyle" Value="true"/>
        <Setter Property="IsTabStop" Value="false"/>
        <Setter Property="Focusable" Value="false"/>
        <Setter Property="ClickMode" Value="Press"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}">
                        <Grid HorizontalAlignment="Right" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}">
                            <Path x:Name="Arrow" Fill="Black" HorizontalAlignment="Center" Margin="3,1,0,0" VerticalAlignment="Center" Data="{StaticResource DownArrowGeometry}"/>
                        </Grid>
                    </Microsoft_Windows_Themes:ButtonChrome>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="true">
                            <Setter Property="RenderPressed" TargetName="Chrome" Value="true"/>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Fill" TargetName="Arrow" Value="#AFAFAF"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <ControlTemplate x:Key="ComboBoxMessageTemplate" TargetType="{x:Type ComboBox}">
        <Grid x:Name="MainGrid" SnapsToDevicePixels="true">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0"/>
            </Grid.ColumnDefinitions>
            <Popup x:Name="PART_Popup" Margin="1" AllowsTransparency="true" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Bottom" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Grid.ColumnSpan="2">
                <Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=MainGrid}" Color="Transparent">
                    <Border x:Name="DropDownBorder" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1">
                       <ScrollViewer CanContentScroll="true">
                                <StackPanel>
                                    <TextBlock x:Name="SelectMessage" HorizontalAlignment="Left" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}" VerticalAlignment="Center" Margin="{TemplateBinding Padding}" Visibility="Visible"/>
                                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.DirectionalNavigation="Contained"/>
                                </StackPanel>
                            </ScrollViewer>
                    </Border>
                </Microsoft_Windows_Themes:SystemDropShadowChrome>
            </Popup>
            <ToggleButton Style="{StaticResource ComboBoxReadonlyToggleButton}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" IsHitTestVisible="false" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"/>

        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="SelectedItem" Value="{x:Null}">
                <Setter Property="Visibility" TargetName="SelectMessage" Value="Visible"/>
            </Trigger>                
            <Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="true">
                <Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
                <Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
            </Trigger>
            <Trigger Property="HasItems" Value="false">
                <Setter Property="Height" TargetName="DropDownBorder" Value="95"/>
            </Trigger>
            <Trigger Property="IsEnabled" Value="false">
                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                <Setter Property="Background" Value="#FFF4F4F4"/>
            </Trigger>
            <Trigger Property="IsGrouping" Value="true">
                <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
</ComboBox.Resources>    

最佳答案

您可以包装 ObservableCollection,这样您就可以使用未修改的 ComboBox。包装器看起来像这样:

class PrefixedObservableCollection<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged
{
    private readonly ObservableCollection<T> _wrappedCollection;
    private readonly T _prefix;

    public IEnumerator<T> GetEnumerator()
    {
        yield return _prefix;
        foreach (T item in _wrappedCollection)
            yield return item;
    }

    // ...  Implement interfaces, etc. Forward along change notifications from wrapped collection.
}

关于c# - 组合框项目源 = ObservableCollection & 我需要在顶部有一个 '-None-' 虚拟条目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2628976/

相关文章:

c# - 在 WPF/C# 中使用全局键盘钩子(Hook) (WH_KEYBOARD_LL)

c# - Windows 窗体中的多级组合框

c# - 从 ASP.NET 与 SQL Mgmt Admin 调用时存储过程速度较慢

c# - 等到事件引发,然后继续代码

wpf - 与 UpdateSourceTrigger==LostFocus 绑定(bind)不会触发菜单或工具栏交互

c# - WPF - 自动刷新组合框内容

c# - 在 Windows 窗体中创建带圆角的自定义 ComboBox

c# - 如何使用或不使用导航属性进行 Linq 多对多连接

javascript - 使用 Razor 形式和模型值而不是当前的 js 对象

wpf - 读取 xml 文件后在 WPF xaml 文件/xaml.cs 文件中动态创建按钮?