JokerMartini
JokerMartini

Reputation: 6147

Binding to a textbox throws bind exception error

I'm trying to bind a textbox to a public string field to filter a list of items in the wpf listbox. I keep getting this error. It's rather simple setup. The code is below. I feel that the code itself is rather simple and I'm not clear as to where the problem is. Help is appreciated!

For some reason my list is always empty and it should initially display the names of all the States, and then if the Search box contains text it filters the list.

enter image description here enter image description here

System.Windows.Data Error: 8 : Cannot save value from target back to source. BindingExpression:Path=SearchText; DataItem='MainWindowViewModel' (HashCode=37975124); target element is 'TextBox' (Name='SearchBox'); target property is 'Text' (type 'String') NullReferenceException:'System.NullReferenceException: Object reference not set to an instance of an object.

VNode.cs

namespace WpfApplication1
{
    public class VNode
    {
        public string Name { get; set; }
    }
}

ObservableObject.cs

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WpfApplication1
{
    public class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

MainWindowViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace WpfApplication1
{
    public class MainWindowViewModel : ObservableObject
    {
        private ObservableCollection<VNode> _vnodes;
        public ObservableCollection<VNode> VNodes
        {
            get { return _vnodes; }
            set
            {
                _vnodes = value;
                NotifyPropertyChanged("VNodes");
            }
        }

        private ObservableCollection<VNode> _vnodesfiltered;
        public ObservableCollection<VNode> VNodesFiltered
        {
            get { return _vnodesfiltered; }
            set
            {
                _vnodesfiltered = value;
                NotifyPropertyChanged("VNodesFiltered");
            }
        }

        public MainWindowViewModel()
        {
            VNodes = new ObservableCollection<VNode>();

            // data testing
            List<string> names = new List<string>() { "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "DistrictofColumbia", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "NewHampshire", "NewJersey", "NewMexico", "NewYork", "NorthCarolina", "NorthDakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "RhodeIsland", "SouthCarolina", "SouthDakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "WestVirginia", "Wisconsin", "Wyoming" };

            foreach (string name in names)
            {
                var node = new VNode();
                node.Name = name;
                VNodes.Add(node);
            }
        }

        private string _searchText = "";
        public string SearchText
        {
            get { return _searchText; }
            set
            {
                if (value != _searchText)
                {
                    _searchText = value;
                    VNodesFiltered.Clear();

                    if (string.IsNullOrWhiteSpace(SearchText))
                    {
                        foreach (var node in VNodes)
                        {
                            VNodesFiltered.Add(node);
                        }
                    }
                    else
                    {
                        foreach (var node in VNodes)
                        {
                            if (node.Name.Contains(SearchText))
                            {
                                VNodesFiltered.Add(node);
                            }
                        }
                    }
                }
            }
        }

    }
}

MainWindow.xaml

<Window x:Class="WpfApplication1.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:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="200"
        WindowStartupLocation="CenterScreen">

    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>

    <Grid>

        <ListBox>
            <ListBox.ContextMenu>
                <ContextMenu FocusManager.FocusedElement="{Binding ElementName=SearchBox}">
                    <ContextMenu.Template>
                        <ControlTemplate>
                            <Border BorderThickness="2" BorderBrush="sc#1,.1,.1,.1" CornerRadius="4" 
                                    Background="sc#1,.05,.05,.05">

                                <Grid>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition Height="*"/>
                                    </Grid.RowDefinitions>

                                    <TextBox Grid.Row="0" Margin="4" MinWidth="150" Name="SearchBox" VerticalAlignment="Center"
                                             Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                                    </TextBox>
                                    <ListBox Grid.Row="1" MinWidth="150" MaxHeight="300" ItemsSource="{Binding VNodes}">
                                        <ListBox.ItemTemplate>
                                            <DataTemplate>
                                                <WrapPanel>
                                                    <TextBlock Text="{Binding Name}" FontWeight="Regular" FontSize="12" />
                                                </WrapPanel>
                                            </DataTemplate>
                                        </ListBox.ItemTemplate>

                                    </ListBox>
                                </Grid>

                            </Border>
                        </ControlTemplate>
                    </ContextMenu.Template>
                </ContextMenu>
            </ListBox.ContextMenu>
        </ListBox>
    </Grid>
</Window>

Upvotes: 1

Views: 989

Answers (2)

Domysee
Domysee

Reputation: 12846

You dont initialize _vnodesfiltered.
The TextBox invokes the setter of SearchText. This setter calls VNodesFiltered.Clear();. But since _vnodesfiltered is null, VNodesFiltered is also null.
Therefore VNodesFiltered.Clear(); throws a NullPointerException.

Because the setter relevant for the Binding expression throws an exception, it cannot write the value to the source, which is exactly what the exception says with

"Cannot save value from target back to source".

The solution is to initialize _vnodesfiltered in your constructor:

public MainWindowViewModel()
{
    VNodes = new ObservableCollection<VNode>();
    _vnodesfiltered = new ObservableCollection<VNode>();

    // data testing
    List<string> names = new List<string>() { "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "DistrictofColumbia", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "NewHampshire", "NewJersey", "NewMexico", "NewYork", "NorthCarolina", "NorthDakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "RhodeIsland", "SouthCarolina", "SouthDakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "WestVirginia", "Wisconsin", "Wyoming" };

    foreach (string name in names)
    {
        var node = new VNode();
        node.Name = name;
        VNodes.Add(node);
    }
}

Upvotes: 2

toadflakz
toadflakz

Reputation: 7944

You have not instantiated VNodesFiltered collection - it's null.

Upvotes: 0

Related Questions