【问题标题】:Equivalent of editable ComboBox in WinRT?相当于 WinRT 中的可编辑组合框?
【发布时间】:2013-04-15 21:33:34
【问题描述】:

标准(桌面)窗口组合框具有三种样式;简单、下拉和下拉列表。 Dropdown 的作用类似于编辑控件和组合框,而 Drop List 不允许编辑。

是我遗漏了什么,还是 Windows 8 商店应用中的 XAML ComboBox 控件仅支持下拉列表样式?

当我遇到这个时,我正在实现一些东西,我越看越觉得它不受支持。

我真的需要用编辑控件后跟列表框替换屏幕中的组合框吗?

呸。

【问题讨论】:

    标签: xaml windows-8 windows-store-apps winrt-xaml


    【解决方案1】:

    感谢 edward.ho.tpe 的回答,我通过在 ComboBoxItem 中使用 TextBox 给自己写了一个小的 EditableComboBox。 如果您想多次使用它,最好创建一个 UserControl。

    但是我是这样做的:

    风格:

    <SolidColorBrush x:Key="TransparentBrush" Color="Transparent"/>
    <Style x:Key="ComboBoxItemTextBox" TargetType="TextBox">
        <Setter Property="MinWidth" Value="{ThemeResource TextControlThemeMinWidth}"/>
        <Setter Property="MinHeight" Value="{ThemeResource TextControlThemeMinHeight}"/>
        <Setter Property="Foreground" Value="{ThemeResource TextBoxForegroundThemeBrush}"/>
        <Setter Property="Background" Value="{StaticResource TransparentBrush}"/>
        <Setter Property="BorderBrush" Value="{StaticResource TransparentBrush}"/>
        <Setter Property="SelectionHighlightColor" Value="{ThemeResource TextSelectionHighlightColorThemeBrush}"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
        <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden"/>
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden"/>
        <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False"/>
        <Setter Property="Padding" Value="{ThemeResource TextControlThemePadding}"/>
        <Setter Property="Margin" Value="-10,0,0,0"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="TextBox">
                    <Grid>
                        <Grid.Resources>
                            <Style x:Name="DeleteButtonStyle" TargetType="Button">
                                <Setter Property="Template">
                                    <Setter.Value>
                                        <ControlTemplate TargetType="Button">
                                            <Grid>
                                                <VisualStateManager.VisualStateGroups>
                                                    <VisualStateGroup x:Name="CommonStates">
                                                        <VisualState x:Name="Normal"/>
                                                        <VisualState x:Name="PointerOver">
                                                            <Storyboard>
                                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="BackgroundElement">
                                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextBoxButtonPointerOverBackgroundThemeBrush}"/>
                                                                </ObjectAnimationUsingKeyFrames>
                                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="BorderElement">
                                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextBoxButtonPointerOverBorderThemeBrush}"/>
                                                                </ObjectAnimationUsingKeyFrames>
                                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="GlyphElement">
                                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextBoxButtonPointerOverForegroundThemeBrush}"/>
                                                                </ObjectAnimationUsingKeyFrames>
                                                            </Storyboard>
                                                        </VisualState>
                                                        <VisualState x:Name="Pressed">
                                                            <Storyboard>
                                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="BackgroundElement">
                                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextBoxButtonPressedBackgroundThemeBrush}"/>
                                                                </ObjectAnimationUsingKeyFrames>
                                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="BorderElement">
                                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextBoxButtonPressedBorderThemeBrush}"/>
                                                                </ObjectAnimationUsingKeyFrames>
                                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="GlyphElement">
                                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextBoxButtonPressedForegroundThemeBrush}"/>
                                                                </ObjectAnimationUsingKeyFrames>
                                                            </Storyboard>
                                                        </VisualState>
                                                        <VisualState x:Name="Disabled">
                                                            <Storyboard>
                                                                <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundElement"/>
                                                                <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BorderElement"/>
                                                            </Storyboard>
                                                        </VisualState>
                                                    </VisualStateGroup>
                                                </VisualStateManager.VisualStateGroups>
                                                <Border x:Name="BorderElement" BorderBrush="{ThemeResource TextBoxButtonBorderThemeBrush}" BorderThickness="{TemplateBinding BorderThickness}"/>
                                                <Border x:Name="BackgroundElement" Background="{ThemeResource TextBoxButtonBackgroundThemeBrush}" Margin="{TemplateBinding BorderThickness}">
                                                    <TextBlock x:Name="GlyphElement" AutomationProperties.AccessibilityView="Raw" Foreground="{ThemeResource TextBoxButtonForegroundThemeBrush}" FontStyle="Normal" FontFamily="{ThemeResource SymbolThemeFontFamily}" HorizontalAlignment="Center" Text="&#xE0A4;" VerticalAlignment="Center"/>
                                                </Border>
                                            </Grid>
                                        </ControlTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </Grid.Resources>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="BackgroundElement">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextBoxDisabledBackgroundThemeBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="BorderElement">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextBoxDisabledBorderThemeBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentElement">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextBoxDisabledForegroundThemeBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="PlaceholderTextContentPresenter">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextBoxDisabledForegroundThemeBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Normal">
                                    <Storyboard>
                                        <DoubleAnimation Duration="0" To="{ThemeResource TextControlBackgroundThemeOpacity}" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundElement"/>
                                        <DoubleAnimation Duration="0" To="{ThemeResource TextControlBorderThemeOpacity}" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BorderElement"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="PointerOver">
                                    <Storyboard>
                                        <DoubleAnimation Duration="0" To="{ThemeResource TextControlPointerOverBackgroundThemeOpacity}" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundElement"/>
                                        <DoubleAnimation Duration="0" To="{ThemeResource TextControlPointerOverBorderThemeOpacity}" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BorderElement"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Focused"/>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="ButtonStates">
                                <VisualState x:Name="ButtonVisible"/>
                                <VisualState x:Name="ButtonCollapsed"/>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Border x:Name="BackgroundElement" Background="{TemplateBinding Background}" Grid.ColumnSpan="2" Margin="{TemplateBinding BorderThickness}" Grid.Row="1" Grid.RowSpan="1"/>
                        <Border x:Name="BorderElement" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Grid.ColumnSpan="2" Grid.Row="1" Grid.RowSpan="1"/>
                        <ContentPresenter x:Name="HeaderContentPresenter" Grid.ColumnSpan="2" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" Foreground="{ThemeResource TextBoxForegroundHeaderThemeBrush}" FontWeight="Semilight" Margin="0,4,0,4" Grid.Row="0"/>
                        <ScrollViewer x:Name="ContentElement" AutomationProperties.AccessibilityView="Raw" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsTabStop="False" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" Margin="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Grid.Row="1" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="Disabled"/>
                        <ContentControl x:Name="PlaceholderTextContentPresenter" Grid.ColumnSpan="2" Content="{TemplateBinding PlaceholderText}" Foreground="{ThemeResource TextBoxPlaceholderTextThemeBrush}" IsHitTestVisible="False" IsTabStop="False" Margin="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Grid.Row="1"/>
                        <Button x:Name="DeleteButton" BorderThickness="{TemplateBinding BorderThickness}" Grid.Column="1" FontSize="{TemplateBinding FontSize}" IsTabStop="False" Grid.Row="1" Style="{StaticResource DeleteButtonStyle}" Visibility="Collapsed" VerticalAlignment="Stretch"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    组合框:

    <ComboBox SelectionChanged="ComboBox_SelectionChanged">
        <ComboBoxItem IsSelected="True">
            <TextBox x:Name="tbComboBox" Style="{StaticResource ComboBoxItemTextBox}" KeyDown="tbComboBox_KeyDown"/>
        </ComboBoxItem>
        <ComboBoxItem>Item 1</ComboBoxItem>
        <ComboBoxItem>Item 2</ComboBoxItem>
        <ComboBoxItem>Item 3</ComboBoxItem>
        <ComboBoxItem>Item 4</ComboBoxItem>
    </ComboBox>
    

    事件处理程序:

    private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.AddedItems.Count == 1 && e.AddedItems[0] != (sender as ComboBox).Items[0])
        {
            (sender as ComboBox).SelectedIndex = 0;
            tbComboBox.Text = (e.AddedItems[0] as ComboBoxItem).Content as String;
        }
    }
    
    private void tbComboBox_KeyDown(object sender, KeyRoutedEventArgs e)
    {
        if (e.Key == Windows.System.VirtualKey.Space)
        {
            if (tbComboBox.SelectionLength > 0)
            {
                tbComboBox.Text = tbComboBox.Text.Remove(tbComboBox.SelectionStart, tbComboBox.SelectionLength);
                tbComboBox.SelectionLength = 0;
            }
            int pos = tbComboBox.SelectionStart;
            tbComboBox.Text = tbComboBox.Text.Insert(pos, " ");
            tbComboBox.SelectionStart = pos + 1;
            e.Handled = true;
        }
    }
    

    所以基本上这是什么:

    正如 edward.ho.tpe 建议将 TextBox 作为 ComboBox 的第一项的内容。 TextBox 有一个自定义样式,可以删除背景、边框,将其向左移动一点(可选 - 但我喜欢它,因为它提供了更多的书写空间),并更改了删除按钮以保持折叠状态。 SelectionChanged 事件处理程序确保TextBox 保持SelectedItem 并且仅根据所选项目的内容更改Text,并且KeyDown 事件处理程序处理空格键,否则会触发ComboBox 的下拉列表。

    【讨论】:

    • 这与Space 和Enter 不稳定
    • 当然不是。你不能两者兼得。您可以输入文本(在这种情况下,空格不应打开下拉菜单),或者您不能输入文本(在这种情况下,您只有一个普通的ComboBox)。您可以在组合框的文本中禁止空格并删除 keydown 但这将是一个相当奇怪的设计选择 imo。
    【解决方案2】:

    Syncfusion Controls for WinRT 也包含一个 ComboBox。但它不是免费的。

    【讨论】:

    • 不幸的是,Syncfusion 的 UWP sfComboBox 不提供访问输入文本的属性或方法。文本输入仅用于搜索组成列表的集合中的项目。
    【解决方案3】:

    由于 WinRT 中的组合框项目可以是任何东西,您可以:

    <ComboBoxItem>
    <TextBox Text="something"/>
    </ComboBoxItem>
    

    当用户单击该项目时,他/她可以编辑其内容。

    由您决定是让编辑结果更改该项目的编辑框,还是仅向该组合框添加一个新的组合框项目。在 LostFocus 事件中处理它。

    【讨论】:

    • 我不认为将TextBoxes 作为ComboBox 的项目是一个好主意,原因有很多。首先,因为它并没有真正解决最初的问题,其次是出于性能原因。
    【解决方案4】:

    你没有错过任何东西。开箱即用的工具箱中没有可编辑的组合框。

    您可能已经尝试过 winrt xaml 工具包@http://winrtxamltoolkit.codeplex.com/ 但这也没有。太糟糕了,因为它是免费的。

    你可能看过 ComponentOne @http://www.componentone.com/SuperProducts/StudioWinRTXAML/ 但这也没有。

    你可能看过 Infragistics @http://www.infragistics.com/products/technology-previews/windows8/ 但该工具包仍处于“预览”阶段。

    你可能看过 Telerik @http://www.telerik.com/products/windows-8/overview.aspx 他们有一个组合框http://www.telerik.com/products/windows-8/controls/combo-box.aspx

    但你可能想要一些免费的东西。 目前没有 Microsoft XAML 工具包。 所以你需要自己构建或者找一个开源项目。 我暂时找不到这样的项目。

    但什么是真正的可编辑组合框?一个标准的组合框和一个文本框,对吧?

    【讨论】:

      【解决方案5】:

      通过设置

      combobox.ComboBoxMode = ComboBoxModes.Editable 
      

      在syncfusion SfComboBox中,您可以编辑组合框。

      问候,

      Elavarasan M

      【讨论】:

        【解决方案6】:

        我知道这是一个老问题,但对于像我这样的新搜索者,我发现 ComboBox.IsEditable 的属性很好

        【讨论】:

          【解决方案7】:

          试试名为AutoSuggestBox的UIControl

          <AutoSuggestBox PlaceholderText="Company">
               <AutoSuggestBox.QueryIcon>
                   <SymbolIcon Symbol="find"/>
               </AutoSuggestBox.QueryIcon>
          </AutoSuggestBox>
          

          【讨论】:

          • 这对于过滤项目很有用,但是如果您想呈现 N 个标准选择,或者允许用户输入自定义值怎么办?这是我的初衷。
          【解决方案8】:

          我到处寻找可搜索组合框,并决定编写自己的组合框。它与您的可编辑组合框不太一样,但会在键入时过滤组合框中的选项。也许这可以帮助某人。

          您可以像这样定义一个新控件:

          <control:SearchableComboBox Margin='5'
                    x:Name='ComboBoxCountry'
                    ItemsSourceList='{Binding CountryList}'
                    ItemsSourceListBase='{Binding CountryListBase}'
                    PlaceholderText='Select Country'/>
          

          很遗憾,您仍然需要提供重复的列表 CountryListBase。如果您有改进的建议,请告诉我!

          using System.Collections.Generic;
          using System.Collections.ObjectModel;
          using System.Linq;
          using Windows.System;
          using Windows.UI.Xaml;
          using Windows.UI.Xaml.Controls;
          using Windows.UI.Xaml.Input;
          
          namespace eMoyoConnect.Controls
          {
              public class SearchableComboBox : ComboBox
              {
          
                  public ObservableCollection<string> ItemsSourceList
                  {
                      get { return (ObservableCollection<string>)GetValue(ItemsSourceListProperty); }
                      set
                      {
                          SetValue(ItemsSourceListProperty, value);
                          this.ItemsSource = ItemsSourceList;
                      }
                  }
          
                  public static readonly DependencyProperty ItemsSourceListProperty =
                      DependencyProperty.Register("ItemsSourceList", typeof(ObservableCollection<string>), typeof(SearchableComboBox),
                      new PropertyMetadata(null, ItemsSourceListChanged));
          
                  private static void ItemsSourceListChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
                  {
                      var plv = d as SearchableComboBox;
                      plv.ItemsSource = e.NewValue;
                  }
          
                  public Collection<string> ItemsSourceListBase
                  {
                      get { return (Collection<string>)GetValue(ItemsSourceListBaseProperty); }
                      set
                      {
                          SetValue(ItemsSourceListBaseProperty, value);
                          this.ItemsSource = ItemsSourceListBase;
                      }
                  }
          
                  public static readonly DependencyProperty ItemsSourceListBaseProperty =
                      DependencyProperty.Register("ItemsSourceListBase", typeof(Collection<string>), typeof(SearchableComboBox),
                      new PropertyMetadata(null, ItemsSourceListBaseChanged));
          
                  private static void ItemsSourceListBaseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
                  {
                      var plv = d as SearchableComboBox;
                      plv.ItemsSource = e.NewValue;
                  }
          
                  string FilterString = "";
                  protected override void OnKeyDown(KeyRoutedEventArgs e)
                  {
                      if (IsLetterOrSpace(e.Key))
                      {
                          if (e.Key == VirtualKey.Space)
                              FilterString += " ";
                          else
                              FilterString += e.Key.ToString();
                          FilterList(FilterString);
                          this.ItemsSource = ItemsSourceList;
                          if (ItemsSourceList.Count > 0)
                              this.SelectedIndex = 0;
                      }
                      else if (e.Key == VirtualKey.Back)
                      {
                          if (FilterString.Length > 0)
                          {
                              FilterString = FilterString.Substring(0, FilterString.Length - 1);
                              FilterList(FilterString);
                              this.ItemsSource = ItemsSourceList;
                              if (ItemsSourceList.Count > 0)
                                  this.SelectedIndex = 0;
                          }
                      }
          
                      if (e.Key != VirtualKey.Space)
                      {
                          base.OnKeyDown(e);
                      }
                  }
          
                  protected override void OnGotFocus(RoutedEventArgs e)
                  {
                      string selectedValue = "";
                      if (this.SelectedValue != null)
                          selectedValue = (string)this.SelectedValue;
                      FilterString = "";
                      FilterList(FilterString);
                      if (!string.IsNullOrEmpty(selectedValue))
                          this.SelectedValue = selectedValue;
                  }
          
                  internal void FilterList(string FilterString)
                  {
                      ItemsSourceList.Clear();
                      IEnumerable<string> list;
                      if (!string.IsNullOrEmpty(FilterString))
                          list = ItemsSourceListBase.Where(x => x.StartsWith(FilterString));
                      else
                          list = ItemsSourceListBase;
                      foreach (var item in list)
                          ItemsSourceList.Add(item);
                  }
          
                  private bool IsLetterOrSpace(VirtualKey key)
                  {
                      return (key == VirtualKey.A
                          || key == VirtualKey.B
                          || key == VirtualKey.C
                          || key == VirtualKey.D
                          || key == VirtualKey.E
                          || key == VirtualKey.F
                          || key == VirtualKey.G
                          || key == VirtualKey.H
                          || key == VirtualKey.I
                          || key == VirtualKey.J
                          || key == VirtualKey.K
                          || key == VirtualKey.L
                          || key == VirtualKey.M
                          || key == VirtualKey.N
                          || key == VirtualKey.O
                          || key == VirtualKey.P
                          || key == VirtualKey.Q
                          || key == VirtualKey.R
                          || key == VirtualKey.S
                          || key == VirtualKey.T
                          || key == VirtualKey.U
                          || key == VirtualKey.V
                          || key == VirtualKey.W
                          || key == VirtualKey.X
                          || key == VirtualKey.Y
                          || key == VirtualKey.Z
                          || key == VirtualKey.Space);
                  }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 2014-06-18
            • 1970-01-01
            • 2014-07-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多