打开下拉列表后,WPF DropDownButton IsOpen绑定中断

时间:2016-12-16 10:31:03

标签: c# wpf binding

我遇到了一个特殊的问题,我在修理时遇到了麻烦。下面是显示问题的简化代码。

我有一个WPF DropDownButton,其中包含下拉列表中的字符串列表。我也有一个搜索框。当您在搜索框中键入内容时,下拉菜单会自动展开并仅显示匹配的项目(从而使您更容易找到您感兴趣的项目)。如果没有匹配的项目或搜索字段为空,则关闭下拉列表。如果存在搜索词但没有匹配项,则搜索字段会更改颜色。

这一切都很好。在此之前,您要么使用它的按钮清除搜索字段(当有清除的东西时),要么使用它的下拉箭头按钮下拉列表。完成其中任何一项操作后,当您更改搜索字词时,下拉列表将不再自动打开和关闭。

一旦“破坏”,搜索仍然有效,您可以搜索某些内容,例如'文本1',如果您打开下拉列表,它只包含匹配的项目。只是自动打开和关闭不再有效。

我已经检查过,ViewModel正在引发正确的事件。我已经查看了DropDownButton代码,并且在它到达OnIsOpenChanged代码时可以看到它,但是一旦被破坏它就不会。

可能是通过'手动'打开下拉列表我打破/覆盖IsOpen绑定吗?如果是这样,我该如何解决这个问题。为什么清除搜索字段也会破坏绑定?删除手动下拉菜单不是一种选择。

修改 在设置我添加的SeachExpression之后,在后面的按钮单击代码(我已经尝试用命令替换,但它对行为没有影响):

 BindingExpression be = BindingOperations.GetBindingExpression(SelectButton, Xceed.Wpf.Toolkit.DropDownButton.IsOpenProperty);

我认为是检查是否存在绑定的正确方法,它返回null。如果我在设置SeachExpression之前执行此操作,则它为非空。

视图模型

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private IList<string> originalText;

    public string SearchExpression
    {
        get
        {
            return _searchExpression;
        }
        set
        {
            if (value == _searchExpression)
                return;

            _searchExpression = value;
            UpdateDescriptions(_searchExpression);
            OnPropertyChanged("SearchExpression");
        }
    }
    string _searchExpression = string.Empty;

    public ReadOnlyObservableCollection<string> Descriptions
    {
        get { return _descriptions; }
        private set
        {
            if (value == _descriptions)
                return;

            _descriptions = value;
            OnPropertyChanged("Descriptions");
        }
    }
    ReadOnlyObservableCollection<string> _descriptions;

    public bool NoMatches 
    {
        get { return _noMatches; }
        private set
        {
            if (value == _noMatches)
                return;

            _noMatches = value;
            OnPropertyChanged("NoMatches");
        }
    }
    bool _noMatches;

    public bool ShowSearchResults
    {
        get { return _showSearchResults; }
        private set
        {
            if (value == _showSearchResults)
                return;

            _showSearchResults = value;
            OnPropertyChanged("ShowSearchResults");
        }
    }
    bool _showSearchResults;

    public ViewModel()
    {
        originalText = new List<string>() {"Text 1", "Text 2", "Text 3"};
        UpdateDescriptions();
    }

    private void UpdateDescriptions(string searchExpression = null)
    {
        ObservableCollection<string> descriptions = new ObservableCollection<string>();

        IEnumerable<string> records;
        if (string.IsNullOrWhiteSpace(searchExpression))
        {
            records = originalText;
            NoMatches = false;
            ShowSearchResults = false;
        }
        else
        {
            records = originalText.Where(x => x.Contains(searchExpression));
            NoMatches = records.Count() < 1;
            ShowSearchResults = records.Count() > 0;
        }

        descriptions = new ObservableCollection<string>(records);

        this.Descriptions = new ReadOnlyObservableCollection<string>(descriptions);
    }

    protected virtual void OnPropertyChanged(string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) 
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

视图

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wpf="clr-namespace:Xceed.Wpf.Toolkit;assembly=WPFToolkit.Extended"
    xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="MainWindow" Height="65" Width="225">

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

    <wpf:DropDownButton Grid.Column="0" x:Name="SelectButton" Content="Select" Margin="3 0" IsOpen="{Binding ShowSearchResults, UpdateSourceTrigger=PropertyChanged}">
        <wpf:DropDownButton.DropDownContent>
            <ListBox x:Name="descriptionsList" MaxHeight="250" ItemsSource="{Binding Path=Descriptions, Mode=OneWay}" HorizontalContentAlignment="Stretch">

                <!-- this code makes sure the ListBox displays at the correct with for the outset, and does not resize as you scroll-->
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel />
                    </ItemsPanelTemplate>
                </ListBox.ItemsPanel>

                <ListBox.ItemContainerStyle>
                    <Style TargetType="ListBoxItem">
                        <Style.Triggers>
                            <Trigger Property="Control.IsMouseOver" Value="True">
                                <Setter Property="Control.Background" Value="{x:Static SystemColors.HighlightBrush}" />
                                <Setter Property="Control.Foreground" Value="{x:Static SystemColors.HighlightTextBrush}" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </ListBox.ItemContainerStyle>
            </ListBox>
        </wpf:DropDownButton.DropDownContent>
    </wpf:DropDownButton>

    <Border Grid.Column="2" Background="White" BorderBrush="Gray" BorderThickness="1">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>

            <xctk:WatermarkTextBox x:Name="searchTextBox" Text="{Binding SearchExpression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Watermark="Search" ToolTip="Search for an item in the list." >
                <xctk:WatermarkTextBox.Style>
                    <Style>
                        <Setter Property="Control.BorderThickness" Value="0" />
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding NoMatches}" Value="True" >
                                <Setter Property="TextBox.Background" Value="Tomato"/>
                                <Setter Property="TextBox.Foreground" Value="White"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </xctk:WatermarkTextBox.Style>
            </xctk:WatermarkTextBox>

            <Button Grid.Column="1"  
                x:Name="ClearButton"
                ToolTip="Clear search text"
                Click="ClearButton_Click" 
                HorizontalAlignment="Center"
                VerticalAlignment="Center">
                <Image Source="/WPFToolkit.Extended;component/PropertyGrid/Images/ClearFilter16.png" Width="16" Height="16" />
            </Button>
        </Grid>
    </Border>
</Grid>

查看代码背后

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new ViewModel();
    }

    private void ClearButton_Click(object sender, RoutedEventArgs e)
    {
        ViewModel vm = this.DataContext as ViewModel;
        if (vm != null)
            vm.SearchExpression = "";
    }
}

0 个答案:

没有答案