4

ドロップダウンが展開されたときに上に表示ComboBoxされる検索ボックスを使用して、検索可能にしたい。検索機能を実現するにはカスタムコントロールを作成する必要があると思いますが、最初は通常のを使用してを表示させようとしています。ドロップダウンを展開しようとすると例外が発生する現在の試みは次のとおりです。TextBoxItemsPanelComboBoxTextBoxComboBox

<Style x:Key="FilteredComboBox" TargetType="ComboBox">
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <StackPanel>
                    <TextBox/>
                    <StackPanel IsItemsHost="True"
                                Orientation="Horizontal"
                                VerticalAlignment="Center"
                                HorizontalAlignment="Center"/>
                    </StackPanel>

            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
</Style>

これが生成している例外は次のとおりです。

ItemsControlのItemsPanelとして使用されるPanelのChildrenコレクションを明示的に変更することはできません。ItemsControlは、Panelの子要素を生成します。

これを自分のやりたいことにする方法があると確信していますが、数時間のグーグルと試行錯誤の末、頭が回転しています。どんな助けでも大歓迎です!

4

4 に答える 4

6

私がこれに対して得た回答はすべて正しい方向に進んでいましたが、解決策としてマークされるほど十分に私の質問に答えたものはないと思いました。最終的には、ComboBoxからカスタムコントロールを派生させました(デザイナーでComboBoxを右クリックし、[テンプレートの編集]-> [コピーの編集]を選択します。これにより、コピーしたComboBoxテンプレートの一連のXAMLコードが生成されます。私が作成したカスタムコントロールプロジェクトのGeneric.xamlファイル)。次に、生成されたXAMLコードのポップアップ部分を編集して、次のようにItemsPresenterの上にWatermarkTextBox(Extended WPF Toolkitから)を追加しました。

<Popup x:Name="PART_Popup" AllowsTransparency="true" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
    <Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=MainGrid}">
    <Border x:Name="DropDownBorder" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
        <ScrollViewer x:Name="DropDownScrollViewer">
        <Grid RenderOptions.ClearTypeHint="Enabled">
            <Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
            <Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=DropDownBorder}" Height="{Binding ActualHeight, ElementName=DropDownBorder}" Width="{Binding ActualWidth, ElementName=DropDownBorder}"/>
            </Canvas>
            <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <xtk:WatermarkTextBox Grid.Row="0"
                          Visibility="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource booleanToVisibilityConverter}}"
                          Watermark="Type here to filter..."
                          Text="{Binding SearchFilter, RelativeSource={RelativeSource TemplatedParent}, UpdateSourceTrigger=PropertyChanged}">
            </xtk:WatermarkTextBox>
            <ItemsPresenter x:Name="ItemsPresenter" Grid.Row="1" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
            </Grid>
        </Grid>
        </ScrollViewer>
    </Border>
    </Themes:SystemDropShadowChrome>
</Popup>

テキストをバインドしているSearchFilterプロパティは、カスタムコントロールの分離コード内のプロパティであり、ComboBox内の値の実際のフィルタリングを実行します。これは私の元の質問の範囲を少し超えていますが、誰かが興味を持った場合に備えて、フィルタリングを行う方法は次のとおりです。

public class SearchableComboBox : ComboBox
{
    public const string SearchFilterPropertyName = "SearchFilter";
    public readonly static DependencyProperty SearchFilterProperty;
    public string SearchFilter
    {
        get { return (string)GetValue(SearchFilterProperty); }
        set { SetValue(SearchFilterProperty, value); }
    }

    static SearchableComboBox()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(SearchableComboBox), new FrameworkPropertyMetadata(typeof(SearchableComboBox)));

        SearchFilterProperty = DependencyProperty.Register(SearchFilterPropertyName, typeof(string), typeof(SearchableComboBox),
            new PropertyMetadata(string.Empty, new PropertyChangedCallback(SearchFilter_PropertyChanged)));

    }

    private static void SearchFilter_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((SearchableComboBox)d).RefreshFilter();
    }

    private void RefreshFilter()
    {
        if (this.ItemsSource != null)
        {
            ICollectionView view = CollectionViewSource.GetDefaultView(this.ItemsSource);
            view.Refresh();
        }
    }

    private bool FilterPredicate(object value)
    {
        if (value == null)
            return false;

        if (string.IsNullOrEmpty(SearchFilter))
            return true;

        return value.ToString().Contains(SearchFilter, StringComparison.CurrentCultureIgnoreCase);
    }

    protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
    {
        if (newValue != null)
        {
            ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
            view.Filter += this.FilterPredicate;
        }

        if (oldValue != null)
        {
            ICollectionView view = CollectionViewSource.GetDefaultView(oldValue);
            view.Filter -= this.FilterPredicate;
        }

        base.OnItemsSourceChanged(oldValue, newValue);
    }
于 2013-02-28T17:29:27.893 に答える
1

msdnの「ComboBoxControlTemplate」を使用できます。

Popupこのスタイルから編集する必要があります 。Gridそこに2行のコントロールを追加しました。私が追加した最初の行では、Extended WPF Toolkit(WatermarkTextBoxTextBox )からより良いオプションがここにあると思います。2行目には、アイテムがあります。WatermarkTextBoxScrollViewer

fromのTextBox最初の行は常に表示ComboBoxされます。アイテムが多数ある場合、これらの要素のみがスクロールコンテンツに含まれます。

以下は完全な例です。

<!-- Fill Brushes -->

<LinearGradientBrush x:Key="NormalBrush" StartPoint="0,0" EndPoint="0,1">
    <GradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Color="#FFF" Offset="0.0"/>
            <GradientStop Color="#CCC" Offset="1.0"/>
        </GradientStopCollection>
    </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="HorizontalNormalBrush" StartPoint="0,0" EndPoint="1,0">
    <GradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Color="#FFF" Offset="0.0"/>
            <GradientStop Color="#CCC" Offset="1.0"/>
        </GradientStopCollection>
    </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="LightBrush" StartPoint="0,0" EndPoint="0,1">
    <GradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Color="#FFF" Offset="0.0"/>
            <GradientStop Color="#EEE" Offset="1.0"/>
        </GradientStopCollection>
    </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="HorizontalLightBrush" StartPoint="0,0" EndPoint="1,0">
    <GradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Color="#FFF" Offset="0.0"/>
            <GradientStop Color="#EEE" Offset="1.0"/>
        </GradientStopCollection>
    </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="DarkBrush" StartPoint="0,0" EndPoint="0,1">
    <GradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Color="#FFF" Offset="0.0"/>
            <GradientStop Color="#AAA" Offset="1.0"/>
        </GradientStopCollection>
    </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="PressedBrush" StartPoint="0,0" EndPoint="0,1">
    <GradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Color="#BBB" Offset="0.0"/>
            <GradientStop Color="#EEE" Offset="0.1"/>
            <GradientStop Color="#EEE" Offset="0.9"/>
            <GradientStop Color="#FFF" Offset="1.0"/>
        </GradientStopCollection>
    </GradientBrush.GradientStops>
</LinearGradientBrush>

<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />

<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />

<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />

<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD" />

<!-- Border Brushes -->

<LinearGradientBrush x:Key="NormalBorderBrush" StartPoint="0,0" EndPoint="0,1">
    <GradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Color="#CCC" Offset="0.0"/>
            <GradientStop Color="#444" Offset="1.0"/>
        </GradientStopCollection>
    </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="HorizontalNormalBorderBrush" StartPoint="0,0" EndPoint="1,0">
    <GradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Color="#CCC" Offset="0.0"/>
            <GradientStop Color="#444" Offset="1.0"/>
        </GradientStopCollection>
    </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="DefaultedBorderBrush" StartPoint="0,0" EndPoint="0,1">
    <GradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Color="#777" Offset="0.0"/>
            <GradientStop Color="#000" Offset="1.0"/>
        </GradientStopCollection>
    </GradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="PressedBorderBrush" StartPoint="0,0" EndPoint="0,1">
    <GradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Color="#444" Offset="0.0"/>
            <GradientStop Color="#888" Offset="1.0"/>
        </GradientStopCollection>
    </GradientBrush.GradientStops>
</LinearGradientBrush>

<SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />

<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />

<SolidColorBrush x:Key="LightBorderBrush" Color="#AAA" />

<!-- Miscellaneous Brushes -->
<SolidColorBrush x:Key="GlyphBrush" Color="#444" />

<SolidColorBrush x:Key="LightColorBrush" Color="#DDD" />

<ControlTemplate x:Key="ComboBoxToggleButton" TargetType="ToggleButton">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition Width="20" />
        </Grid.ColumnDefinitions>
        <Border
            x:Name="Border" 
            Grid.ColumnSpan="2"
            CornerRadius="2"
            Background="{StaticResource NormalBrush}"
            BorderBrush="{StaticResource NormalBorderBrush}"
            BorderThickness="1" />
        <Border 
            Grid.Column="0"
            CornerRadius="2,0,0,2" 
            Margin="1" 
            Background="{StaticResource WindowBackgroundBrush}" 
            BorderBrush="{StaticResource NormalBorderBrush}"
            BorderThickness="0,0,1,0" />
        <Path 
            x:Name="Arrow"
            Grid.Column="1"     
            Fill="{StaticResource GlyphBrush}"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Data="M 0 0 L 4 4 L 8 0 Z"/>
    </Grid>
    <ControlTemplate.Triggers>
        <Trigger Property="ToggleButton.IsMouseOver" Value="true">
            <Setter TargetName="Border" Property="Background" Value="{StaticResource DarkBrush}" />
        </Trigger>
        <Trigger Property="ToggleButton.IsChecked" Value="true">
            <Setter TargetName="Border" Property="Background" Value="{StaticResource PressedBrush}" />
        </Trigger>
        <Trigger Property="IsEnabled" Value="False">
            <Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
            <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
            <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
            <Setter TargetName="Arrow" Property="Fill" Value="{StaticResource DisabledForegroundBrush}" />
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

<ControlTemplate x:Key="ComboBoxTextBox" TargetType="TextBox">
    <Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}" />
</ControlTemplate>

<Style x:Key="{x:Type ComboBox}" TargetType="ComboBox">
    <Setter Property="SnapsToDevicePixels" Value="true"/>
    <Setter Property="OverridesDefaultStyle" Value="true"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
    <Setter Property="MinWidth" Value="120"/>
    <Setter Property="MinHeight" Value="20"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ComboBox">
                <Grid>
                    <ToggleButton 
                        Name="ToggleButton" 
                        Template="{StaticResource ComboBoxToggleButton}" 
                        Grid.Column="2" 
                        Focusable="false"
                        IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
                        ClickMode="Press">
                    </ToggleButton>
                    <ContentPresenter
                        Name="ContentSite"
                        IsHitTestVisible="False" 
                        Content="{TemplateBinding SelectionBoxItem}"
                        ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
                        ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
                        Margin="3,3,23,3"
                        VerticalAlignment="Center"
                        HorizontalAlignment="Left" />
                    <TextBox x:Name="PART_EditableTextBox"
                             Style="{x:Null}" 
                             Template="{StaticResource ComboBoxTextBox}" 
                             HorizontalAlignment="Left" 
                             VerticalAlignment="Center" 
                             Margin="3,3,23,3"
                             Focusable="True" 
                             Background="Transparent"
                             Visibility="Hidden"
                             IsReadOnly="{TemplateBinding IsReadOnly}"/>
                    <Popup 
                        Name="Popup"
                        Placement="Bottom"
                        IsOpen="{TemplateBinding IsDropDownOpen}"
                        AllowsTransparency="True" 
                        Focusable="False"
                        PopupAnimation="Slide">
                        <Grid 
                            Name="DropDown"
                            SnapsToDevicePixels="True"                
                            MinWidth="{TemplateBinding ActualWidth}"
                            MaxHeight="{TemplateBinding MaxDropDownHeight}">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="30" />
                                <RowDefinition Height="{TemplateBinding MaxDropDownHeight}" />
                            </Grid.RowDefinitions>

                            <Border 
                                x:Name="DropDownBorder"
                                Background="{StaticResource WindowBackgroundBrush}"
                                BorderThickness="1"
                                BorderBrush="{StaticResource SolidBorderBrush}"
                                Grid.RowSpan="2"/>

                            <TextBox Margin="2" VerticalAlignment="Center" />

                            <ScrollViewer Grid.Row="1" Margin="4,6,4,6" SnapsToDevicePixels="True">
                                <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
                            </ScrollViewer>
                        </Grid>
                    </Popup>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="HasItems" Value="false">
                        <Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
                    </Trigger>
                    <Trigger Property="IsGrouping" Value="true">
                        <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                    </Trigger>
                    <Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
                        <Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
                        <Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
                    </Trigger>
                    <Trigger Property="IsEditable"
                             Value="true">
                        <Setter Property="IsTabStop" Value="false"/>
                        <Setter TargetName="PART_EditableTextBox" Property="Visibility"    Value="Visible"/>
                        <Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
    </Style.Triggers>
</Style>
于 2013-02-26T19:12:47.513 に答える
0

はい、それはたくさんのコードですが、これはあなたがリソース辞書の使用について考え始めるべきときです。私は他のポスターに同意します。ユーザーが注意を怠ってフォーカスを失うとコンボボックスが収縮するため、この種の制御は頭痛の種になる可能性があります。

  <Style x:Key="MyCombo" TargetType="{x:Type ComboBox}">
        <Setter Property="Template">
            <Setter.Value>
            <ControlTemplate 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" AllowsTransparency="true" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
                        <Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=MainGrid}">
                            <Border x:Name="DropDownBorder" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
                                <ScrollViewer x:Name="DropDownScrollViewer">
                                    <Grid RenderOptions.ClearTypeHint="Enabled">
                                        <StackPanel>
                                            <TextBox>blah blah</TextBox>


                                            <Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
                                                <Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=DropDownBorder}" Height="{Binding ActualHeight, ElementName=DropDownBorder}" Width="{Binding ActualWidth, ElementName=DropDownBorder}"/>
                                            </Canvas>
                                            <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                        </StackPanel>
                                    </Grid>
                                </ScrollViewer>
                            </Border>
                        </Microsoft_Windows_Themes:SystemDropShadowChrome>
                    </Popup>
                    <ToggleButton BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ComboBoxReadonlyToggleButton}"/>
                    <ContentPresenter ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="false" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <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>
                    <Trigger Property="ScrollViewer.CanContentScroll" SourceName="DropDownScrollViewer" Value="false">
                        <Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}"/>
                        <Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
于 2013-02-26T19:21:15.547 に答える
0

あなたはいくつかの問題を抱えていると思います。

  1. テキストボックスを表示するスタイルに依存している場合、そのテキストボックスのロジックをどこに配置しますか?そのロジックを追加するか、ある種の複合コントロールを作成するには、コンボボックスを拡張する必要があります。

  2. 2番目の問題は、コンボボックスがフォーカスを失うと、その性質上閉じてしまうことです。したがって、その動作を変更するには、いくつかのロジックを作成する必要があります。

それは不可能ではありません。スタイルを作成する以上のことをする必要があると思います。

于 2013-02-26T22:54:01.603 に答える