2

我在最近被重构为使用 MVVM 模式的 WPF 应用程序中有一个 ComboBox。此更改的一个明显副作用是,在组合框下拉列表可见时将焦点更改到另一个应用程序会完全阻止下拉列表再次可见,直到重新启动应用程序。

ComboBox DataContext 设置为我的 ViewModel,其 ItemsSource 绑定到一个ObservableCollection<String> SearchSuggestions,并且 IsDropdownOpen 绑定到SuggestionsVisibleViewModel 中的一个属性。

所需的效果是带有自动完成建议的搜索框。如果 ObservableCollection 中没有建议,如果用户取消搜索,如果用户运行搜索,或者如果用户点击离开文本字段 - 无论是在应用程序内部还是外部,它都应该关闭。

ViewModel 根据用户输入后 SearchSuggesions 是否包含任何项目,将 SuggestionsVisible 属性显式设置为 true 或 false。在此错误出现后,此过程将继续发生,只是对 UI 没有可见的更改。知道为什么在下拉菜单打开时失去焦点会导致下拉菜单在应用程序的其余会话中无法打开吗?

这是我将事物连接在一起的方式:

<ComboBox DataContext="{Binding SearchBoxVm}" Name="cmboSearchField" Height="0.667" 
          VerticalAlignment="Top" IsEditable="True" StaysOpenOnEdit="True" 
          PreviewKeyUp="cmboSearchField_OnKeyUp" 
          PreviewMouseLeftButtonUp="cmboSearchField_OnPreviewMouseLeftButtonUp" 
          Background="White" ItemsSource="{Binding SearchTopics}" 
          IsDropDownOpen="{Binding SuggestionsVisible, 
          UpdateSourceTrigger=PropertyChanged}" 
          Margin="50.997,15.333,120.44,0" 
          RenderTransformOrigin="0.5,0.5" Grid.Row="1" >

<!-- SNIP STYLING -->
</ComboBox>

视图模型:

public class SearchBoxViewModel : INotifyPropertyChanged
{
    public void ResetSearchField(bool preserveContents = false)
    {
        if (!preserveContents || string.IsNullOrEmpty(Query))
        {
            Foreground = Brushes.Gray;
            QueryFont = FontStyles.Italic;
            Query = DEFAULT_TEXT;
        }
    }

    public bool OnKeyUp(Key key)
    {
        bool showDropdown = SuggestionsVisible;
        bool changeFocusToCombobox = false;

        if (keyInValidRange(key))
        {
            SearchSuggestions = GetSearchSuggestions(Query);
            if (SearchSuggestions.Count > 0)
            {
                SuggestionsVisible = true;
            }
        }

        return changeFocusToCombobox;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    bool _suggestionsVisible = false;
    public bool SuggestionsVisible 
    {
        get { return _suggestionsVisible; }
        set
        { 
                    // this section is still called after this issue manifests,
                    // but no visible change to the UI state is made
            _suggestionsVisible = value;
            NotifyPropertyChanged("SuggestionsVisible");
        }
    }

    public ObservableCollection<String> SearchTopics = new ObservableCollection<String>();
 }

OnKeyUp() 方法由 MainWindow 类调用(还没有将事件绑定到 ViewModel 中指定的处理程序),同时也从 MainWindow 调用 ResetSearechField:

// Note: removing references to this event handler does not have any effect
// on the issue at hand... only including here for completeness
void window_Deactivated(object sender, EventArgs e)
{
    SearchBoxVm.SuggestionsVisible = false; 
    SearchBoxVm.ResetSearchField(true);            
}

我花了相当多的时间尝试调试它,并且没有看到任何可能导致此问题的内部状态更改。NotifyPropertyChanged 事件的行为与以前一样,并且堆栈跟踪窗口未显示遇到任何异常。

在 XAML 中将 IsDropdownOpen 属性上的绑定模式设置为“TwoWay”也没有任何效果。最后,在主线程的 Dispatcher 调用中包装对 SuggestionsVisible 的分配对问题也没有影响。

任何援助将不胜感激。

4

1 回答 1

1

我可能应该把它写成评论,但不幸的是,评论不支持图像,所以我会把它作为答案发布,所以如果这根本不相关,请随时投反对票。

@BrMcMullin,因为您已经说过:

所需的效果是带有自动完成建议的搜索框。

请问,您为什么选择使用标准 ComboBox 而不是WPF Toolkit - 2010 年 2 月发行版中提供的专用AutoCompleteBox ,并且似乎是专为您的情况设计的?

您可能已经注意到,第一个链接指向其 Silverlight 前身的文档,但不用担心 - WPF 工具包库包含来自 Silverlight 的 AutoCompleteBox 的功能齐全的官方 WPF 端口。有关此“事件”的更多信息:AutoCompleteBox: Now with 100% more WPF

使用该控件,您的自动完成弹出窗口看起来很简单:

简单的 WPF AutoCompleteBox 示例

或复杂如:

复杂的 WPPF AutoCompleteBox

因此,如果您无法通过 ComboBox 的弹出可见性解决您的问题,请随时尝试 AutoCompleteBox。如果需要,您甚至可以利用它对您的建议进行动态排序(只需使用来自@adabyron 的答案)。

于 2013-07-23T13:14:48.547 回答