Sigh-AniDe
Sigh-AniDe

Reputation: 237

UserControl doesnt display collection from binding

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

Answers (1)

Clemens
Clemens

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

Related Questions