Reputation: 237
I've been trying to create a user control, using this article as my start.
My end result would be supplying a collection and using the TextBox
to filter the collection, displaying the filtered result in the ListView
.
Problem is, it seems that my binding isn't working correctly. The collection isn't being passed through to the UserControl
. Bear in mind, this is my first shot at creating a UserControl
. Why would this happen?
SearchList.Xaml
<UserControl x:Class="CreatingControls.SearchList"
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"
xmlns:local="clr-namespace:CreatingControls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Loaded="SearchList_OnLoaded">
<StackPanel>
<TextBox Name="txtFilter"
TextChanged="txtFilter_TextChanged"
Margin="5" FontSize="20" />
<TextBox IsEnabled="False" Text="Search:"
FontSize="16" BorderThickness="0" />
<ListView Name="listView"
SelectedValue="{Binding Path=SelectedItem}"
DisplayMemberPath="Value"
BorderBrush="LightGray" Margin="5" />
</StackPanel>
SearchList.xaml.cs
public partial class SearchList : UserControl
{
#region AllItems
public List<Collection> AllItems
{
get { return (List<Collection>)GetValue(AllItemsProperty); }
set { SetValue(AllItemsProperty, value); }
}
public static readonly DependencyProperty AllItemsProperty =
DependencyProperty.Register("AllItems", typeof(List<Collection>),
typeof(SearchList), new PropertyMetadata(default(List<Collection>)));
#endregion
#region SelectedItem
public Collection SelectedItem
{
get { return (Collection)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(Collection),
typeof(SearchList), new PropertyMetadata(default(Collection)));
#endregion
public SearchList()
{
InitializeComponent();
listView.ItemsSource = AllItems;
if (listView.ItemsSource != null)
{
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(listView.ItemsSource);
view.Filter = ItemsFilter;
}
}
private void SearchList_OnLoaded(object sender, RoutedEventArgs e)
{
if (listView.ItemsSource == null)
return;
CollectionViewSource.GetDefaultView(listView.ItemsSource).Filter = ItemsFilter;
}
private void txtFilter_TextChanged(object sender, TextChangedEventArgs e)
{
if (listView.ItemsSource == null)
return;
CollectionViewSource.GetDefaultView(listView.ItemsSource).Refresh();
}
private bool ItemsFilter(object item)
{
if (listView.ItemsSource == null)
return false;
if (String.IsNullOrEmpty(txtFilter.Text))
return true;
var collectionItem = (Collection)item;
return (collectionItem.Value.StartsWith(txtFilter.Text, StringComparison.OrdinalIgnoreCase) || collectionItem.Value.StartsWith(txtFilter.Text, StringComparison.OrdinalIgnoreCase));
}
}
Collection.cs
public class Collection : INotifyPropertyChanged
{
private string _id;
public string Id
{
get { return _id; }
set { SetField(ref _id, value, "Id"); }
}
private string _value;
public string Value
{
get { return _value; }
set { SetField(ref _value, value, "Value"); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, string propertyName)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
}
MainWindow.xaml (Window that calls the UserControl created)
<Window x:Class="CreatingControls.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:uControls="clr-namespace:CreatingControls"
mc:Ignorable="d"
d:DataContext="Models."
Title="MainWindow" >
<Grid>
<uControls:SearchList x:Name="slist" />
</Grid>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public static List<Collection> items { get; set; }
public User SelectedUser { get; set; }
public MainWindow()
{
InitializeComponent();
items = new List<Collection>();
items.Add(new Collection { Id = "1", Value = "A" });
items.Add(new Collection { Id = "2", Value = "B" });
items.Add(new Collection { Id = "3", Value = "C" });
items.Add(new Collection { Id = "4", Value = "D" });
items.Add(new Collection { Id = "5", Value = "E" });
items.Add(new Collection { Id = "6", Value = "F" });
items.Add(new Collection { Id = "7", Value = "G" });
items.Add(new Collection { Id = "8", Value = "H" });
slist.AllItems = items;
}
}
Upvotes: 1
Views: 59
Reputation: 128062
You are assigning
listView.ItemsSource = AllItems;
in the SearchList constructor. Later, in the MainWindow constructor, you do
slist.AllItems = items;
Now you seem to be under the impression that listView.ItemsSource
magically holds a reference to the items
collection of your MainWindow. That is not the case.
Instead of the direct assignment, use data binding. In the SearchList XAML, write this:
<ListView ItemsSource="{Binding AllItems,
RelativeSource={RelativeSource AncestorType=UserControl}}" .../>
and remove listView.ItemsSource = AllItems
from the SearchList constructor.
Upvotes: 2