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