我在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”的框,但命令仍然被禁用:
一旦我在下拉列表中选择了该项目,命令按钮就会按预期启用(尽管按钮被禁用时按钮上的图像不会显示为灰色,因此它不完全是我想要的很明显。)
(屏幕截图并没有真正显示,但该搜索只有一个匹配)
如果我在此点击按钮,它会按预期工作。问题是如果我在之后的下拉列表中进行了新的选择,文本框将被清除而不是显示我选择的项目,并且有一个奇怪的延迟,在此期间框显示选择的空格< / em> - 只有当搜索文本与多个条目匹配时,如果在下拉列表中选择了一个值后才进行上一次选择,例如上面的“睡眠”。
在清除框后,我可以从下拉列表中进行新选择,它将按预期工作(除了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
枚举的SearchResult
和switch
es中获取DeclarationType
以返回包含uri的内容指向要在下拉列表中使用的.png图像。