为什么我的下拉式感觉如此笨重?

时间:2015-05-21 05:08:26

标签: c# wpf xaml

我在WinForms / WPF Interop UserControl控件中嵌入了一个XAML ElementHost。控件非常简单 - 它只是一个带按钮的下拉列表 - 这是整个标记:

<UserControl x:Class="Rubberduck.UI.FindSymbol.FindSymbolControl"
             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:local="clr-namespace:Rubberduck.UI.FindSymbol"
             mc:Ignorable="d" 
             d:DesignHeight="27" d:DesignWidth="270">

    <UserControl.Resources>
        <local:DeclarationImageConverter x:Key="DeclarationImageConverter" />
    </UserControl.Resources>

    <UserControl.CommandBindings>
        <CommandBinding Command="local:FindSymbolControl.GoCommand" 
                        Executed="CommandBinding_OnExecuted"
                        CanExecute="CommandBinding_OnCanExecute"/>
    </UserControl.CommandBindings>

    <Grid>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="32" />
        </Grid.ColumnDefinitions>

        <ComboBox IsEditable="True"
                    ItemsSource="{Binding MatchResults}"
                    SelectedItem="{Binding SelectedItem, UpdateSourceTrigger=PropertyChanged}"
                    Text="{Binding SearchString, UpdateSourceTrigger=PropertyChanged}"
                    IsTextSearchCaseSensitive="False"
                    IsTextSearchEnabled="True"
                    TextSearch.TextPath="IdentifierName">
            <ComboBox.ItemTemplate>
                <DataTemplate DataType="local:SearchResult">
                    <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                        <Image Height="16" Width="16" Margin="2,0,2,0" Source="{Binding Declaration, Converter={StaticResource DeclarationImageConverter}}" />
                        <TextBlock Margin="2,0,2,0" Text="{Binding IdentifierName}" FontWeight="Bold" MinWidth="140" />
                        <TextBlock Margin="2,0,2,0" Text="{Binding Location}" />
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

        <Button Grid.Column="1"
                Command="local:FindSymbolControl.GoCommand">
            <Image Height="16" Source="pack://application:,,,/Rubberduck;component/Resources/arrow.png" />
        </Button>

    </Grid>
</UserControl>

问题是它不能可靠,并且远离本能地

  • 如果我在实际匹配项目的框中键入内容,则在我在下拉列表中手动选择该项目之前不会发生任何事情。就像在这里一样,我输入“sleepD”,自动填充到“sleepDelay”的框,但命令仍然被禁用:

    typed "sleepD", autocompleted to "sleepDelay", but command is still disabled

  • 一旦我在下拉列表中选择了该项目,命令按钮就会按预期启用(尽管按钮被禁用时按钮上的图像不会显示为灰色,因此它不完全是我想要的很明显。)

    "sleepDelay" works once it's selected from the dropdown

    (屏幕截图并没有真正显示,但该搜索只有一个匹配)

  • 如果我在此点击按钮,它会按预期工作。问题是如果我在之后的下拉列表中进行了新的选择,文本框将被清除而不是显示我选择的项目,并且有一个奇怪的延迟,在此期间框显示选择的空格< / em> - 只有当搜索文本与多个条目匹配时,如果在下拉列表中选择了一个值后才进行上一次选择,例如上面的“睡眠”。

    wtf is this selected whitespace crap?

  • 在清除框后,我可以从下拉列表中进行新选择,它将按预期工作(除了VBE实际上不会激活CodePane我将选择设置为,但这是一个单独的问题)。

命令实现只会引发一个Navigate事件,该事件将Declaration传递给拥有VM实例的代码。

Search方法,我需要在.Take(50)之后添加.Select,以限制返回结果的数量,并可能稍微减少延迟:

    private void Search(string value)
    {
        var lower = value.ToLowerInvariant();
        var results = _declarations.Where(
            declaration => declaration.IdentifierName.ToLowerInvariant().Contains(lower))
            .OrderBy(declaration => declaration.IdentifierName.ToLowerInvariant())
            .Select(declaration => new SearchResult(declaration));

        MatchResults = new ObservableCollection<SearchResult>(results);
    }

    private string _searchString;

    public string SearchString
    {
        get { return _searchString; }
        set
        {
            _searchString = value; 
            Search(value);
        }
    }

    private SearchResult _selectedItem;

    public SearchResult SelectedItem
    {
        get { return _selectedItem; }
        set 
        { 
            _selectedItem = value; 
            OnPropertyChanged();
        }
    }

    private ObservableCollection<SearchResult> _matchResults;

    public ObservableCollection<SearchResult> MatchResults
    {
        get { return _matchResults; }
        set { _matchResults = value; OnPropertyChanged(); }
    }
}

还涉及IValueConverter,它会在声明Declaration枚举的SearchResultswitch es中获取DeclarationType以返回包含uri的内容指向要在下拉列表中使用的.png图像。