views:

443

answers:

2

I'm trying to implement a real-time updating search bar which updates a TreeView when search phrase changes, however I don't quite manage to get it to update the way I want.

All the items are present in the treeview at application startup (it only contains one level of children at the moment). The SearchPhrase property is also updating correctly when I type in the textbox and the PropertyChanged event invoked, however the Items get is not invoked. My guess is that it has something to do with the presentation models Items property. Am I right?

Here's my XAML:

<Border BorderBrush="Black">
        <TextBox VerticalAlignment="Top" x:Name="phrase" Text="{ Binding      Path=SearchPhrase, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged }" Height="24" />
    </Border>
    <TreeView  Height="200" Background="Gainsboro" Name="list" ItemsSource="{ Binding Path=Items, Mode=OneWay, UpdateSourceTrigger=PropertyChanged }" ItemTemplate="{StaticResource dataTemplate}" />

And here's my presentation model:

public class ProjectListPM : BasePM
{
    private List<AnalysisInfo> items;
    private String searchPhrase;

    /// <summary>
    /// Gets or sets the search phrase.
    /// </summary>
    public String SearchPhrase { 
        get
        {
            return this.searchPhrase;
        }
        set
        {
            if (value != null)
            {
                this.searchPhrase = value;
                FirePropertyChanged<ProjectListPM>(o => o.SearchPhrase);
            }
        }
    }

    /// <summary>
    /// The list of analysises to display in the list.
    /// </summary>
    public List<AnalysisInfo> Items { 
        get
        {
            return
                items.OrderByDescending(i => i.GetSearchRelevanceTo(SearchPhrase)).Where(
                    i => i.GetSearchRelevanceTo(SearchPhrase) > 0).ToList();
        }
        set
        {
            if (value != null)
            {
                this.items = value;
                FirePropertyChanged<ProjectListPM>(o => o.Items);
            }
        }
    }

    public ProjectListPM()
    {
        this.items = new List<AnalysisInfo>();
        this.SearchPhrase = String.Empty;
    }
}

public class BasePM : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Called when a property is changed.       
    /// </summary>
    /// <typeparam name="T">Type</typeparam>
    /// <param name="exp">Function</param>
    protected void FirePropertyChanged<T>(Expression<Func<T, Object>> exp)
    {
        string propertyName;
        if (exp.Body is UnaryExpression)
            propertyName = ((MemberExpression)((UnaryExpression)exp.Body).Operand).Member.Name;
        else
            propertyName = ((MemberExpression)exp.Body).Member.Name;
        if (PropertyChanged != null)
        {
            //Switch to UI thread
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
A: 

Is your List class one that WPF can use? I'd suggest using System.Collections.ObjectModel.ObservableCollection since it already implements list change events compatible with WPF.

Jay
+1  A: 

It looks like you want to filter the items collection of the tree view based on the search phrase.

As an immediate solution you could add a line to the SearchPhrase setter:

set { if (value != null) { this.searchPhrase = value; FirePropertyChanged(o => o.SearchPhrase); FirePropertyChanged(0 => o.Items); } }

This will notify the UI to refresh the Items anytime you set the SearchPhrase.

If you would like to entertain a different approach, you could extend BasePM from ItemsControl, set the ItemsSource and Items.Filter properties in the constructor, and call Items.Refresh() when setting the SearchPhrase.

Josh
this was exactly the solution I found myself. Thanks, though :)
atsjoo