为什么我不能在 WPF 的文本框中反映列表框的选择?

Why can't I reflect a list box choice in a text box in WPF?

我是 WPF 的新手,我在使用现有设置时遇到了一些问题,无法让列表框选择的项目显示在文本框中。

这里的图片代表了问题。我在文本框中键入“12 HOUR”,然后将列表框过滤为字符串中任意位置带有“12 HOUR”的那些项目。但是,当我在列表框中单击“12 小时鼻腔”时,我现在想在文本框中反映该选择:

http://i.imgur.com/ZCYAolT.png

这是我的 XAML 包含列表框和文本框的用户控件:

<UserControl x:Class="SCM_AllergyRecModule.SearchAndSelectView"
         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" 
         mc:Ignorable="d">
<StackPanel Width="300">
    <TextBox x:Name="Filter" Text="{Binding Path=Filter, UpdateSourceTrigger=PropertyChanged}"/>
    <ListBox Width ="300" Height="50" x:Name="ListBoxControl"
           ItemsSource="{Binding Path=Allergens}"            
           SelectedItem="{Binding Path=SelectedAllergen}">         
    </ListBox>
</StackPanel>

这是 ViewModel:

namespace SCM_AllergyRecModule
{
public class SearchAndSelectViewModel
{
    private ICollectionView allergens;
    private string selectedAllergen;
    private string filter = "";      

    public string Filter
    {
        get
        {
            return this.filter.ToUpperInvariant();
        }
        set
        {
            if (this.filter != value)
            {
                this.filter = value;
                this.Allergens.Refresh();
            }
        }
    }

    private bool ContainsFilter(object item)
    {
        var product = item as string;
        if (product == null)
        {
            return false;
        }

        if (string.IsNullOrEmpty(this.Filter))
        {
            return true;
        }

        if (product.ToUpperInvariant().Contains(this.Filter))
        {
            return true;
        }

        return false;
    }

    public SearchAndSelectViewModel()
    {
        var cvs = new CollectionViewSource();
        cvs.Source = MainWindow.scmAllergens;
        this.allergens = cvs.View;
        this.allergens.Filter = ContainsFilter;
    }

    public ICollectionView Allergens
    {
        get
        {
            return this.allergens;
        }
    }

    public string SelectedAllergen
    {
        get
        {
            return this.selectedAllergen;
        }
        set
        {
            if (this.selectedAllergen != value)
            {
                this.selectedAllergen = value;
            }
        }
    }
}
}

更新 1

我将 INotifyPropertyChanged 接口添加到我的 class 并在 setter 中的 SelectedAllergen 上引发它。我添加了一个名为 SearchAndSelectViewModel_PropertyChanged 的事件处理程序来处理 SelectedAllergen 属性 更改并将其设置在构造函数中。

现在,当我单击列表框中的一个项目时,我确实看到它将过滤器设置为 SelectedItem,列表过滤器设置为该项目,因此没有其他显示。但是,文本框文本仍然没有改变?请参见下面的屏幕截图。这是在我在文本框中输入 "PEAN" 之后,然后列表框筛选为两个选项,我选择了 "PEANUTS (FOOD)",然后重新筛选列表框以仅显示该选项但未设置文本框到 "PEANUTS (FOOD)":

http://imgur.com/dNxuVI5

已更新 ViewModel

public class SearchAndSelectViewModel : INotifyPropertyChanged
{
    private ICollectionView allergens;
    private string selectedAllergen;
    private string filter;

    public string Filter
    {
        get
        {
            return this.filter.ToUpperInvariant();
        }
        set
        {
            if (this.filter != value)
            {
                this.filter = value;
                this.Allergens.Refresh();
            }
        }
    }

    private bool ContainsFilter(object item)
    {
        var product = item as string;
        if (product == null)
        {
            return false;
        }


        if (string.IsNullOrEmpty(this.Filter))
        {
            return true;
        }


        if (product.ToUpperInvariant().Contains(this.Filter))
        {
            return true;
        }

        return false;
    }

    private void SearchAndSelectViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        switch (e.PropertyName)
        {
            case "SelectedAllergen":
                this.Filter = this.SelectedAllergen;
                break;
        }
    }

    public SearchAndSelectViewModel()
    {
        filter = "";
        var cvs = new CollectionViewSource();
        cvs.Source = MainWindow.scmAllergens;
        this.allergens = cvs.View;
        this.allergens.Filter = ContainsFilter;
        this.PropertyChanged += SearchAndSelectViewModel_PropertyChanged;
    }

    public ICollectionView Allergens
    {
        get
        {
            return this.allergens;
        }
    }

    public string SelectedAllergen
    {
        get
        {
            return this.selectedAllergen;
        }
        set
        {
            if (this.selectedAllergen != value && value != null)
            {
                this.selectedAllergen = value;
                OnPropertyChanged("SelectedAllergen");
            }
        }
    }

    // INotifyPropertyChanged implementation
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

您需要实现 INotifyPropertyChanged 接口,您可以在 属性 setter 中提出它。由于您还将文本框绑定到过滤器 属性,因此您需要在 SelectedAllergen 更改时设置过滤器 属性。

INotifyPropertyChanged 示例:

public class MyViewModel : INotifyPropertyChanged
{
    //...

    private int myProperty = 0;
    public int MyProperty 
    {
        get { return myProperty; }
        set
        {
            myProperty = value;

            // Raise the property changed notification
            OnPropertyChanged("MyProperty");
        }
    }


    // INotifyPropertyChanged implementation
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if(handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}