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

时间:2016-02-18 21:43:53

标签: c# wpf xaml mvvm user-controls

我是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接口添加到我的类中,并在setter中的SelectedAllergen上引发它。我添加了一个名为SearchAndSelectViewModel_PropertyChanged的事件处理程序来处理SelectedAllergen属性更改并在构造函数中设置它。

现在,当我单击列表框中的某个项目时,我确实看到它将Filter设置为SelectedItem,列表会过滤到该项目,因此没有其他内容显示。但是,文本框文本是不是在变化?见下面的截图。这是在我在文本框中键入“PEAN”之后,然后将列表框过滤为两个选项,然后我选择“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));
        }
    }
}

1 个答案:

答案 0 :(得分:0)

您需要实现INotifyPropertyChanged接口,并且可以在属性设置器中引发它。由于您还将TextBox绑定到Filter属性,因此需要在SelectedAllergen更改时设置Filter属性。

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));
        }
    }
}