I am trying to use a filter for a ListView upon and on initialization, the project is throwing a Null Pointer for the ListView, even though I am setting it in the Constructor and the binding. Here is my code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var viewModel = new MainViewModel();
this.ProjectListView.ItemsSource = viewModel.Projects;
And here is the XAML that refernces it.
<ListView x:Name="ProjectListView" Margin="0,0,10,0" ItemsSource="{Binding Projects}" FontSize="16" Foreground="Black">
I am not sure why the ItemSource is null if it is initialized in the Constructor. Is there a PropertyChanged binding I need to apply?
Here's most of my XAML
<TextBox x:Name="FolderNameBox" Grid.Column="1" Background="White" Grid.Row="1" Grid.ColumnSpan="5"
Margin="0,0,287,654.333" VerticalContentAlignment="Center"
Padding="6" FontSize="16"
IsReadOnly="True"
Text="{Binding ElementName=Hierarchy, Path=SelectedItem.Path, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}">
</TextBox>
<TextBox x:Name="SearchProjectsBox" Grid.Column="5" Background="White" Grid.Row="1" Text="Search Projects"
Margin="47.333,0,0,654.333" VerticalContentAlignment="Center" Foreground="LightGray" Padding="6" FontSize="16" HorizontalAlignment="Left" Width="268" GotFocus="TextBox_GotFocus" LostFocus="TextBox_LostFocus" TextChanged="FilterListView"/>
<TreeView x:Name="Hierarchy" Grid.Column="4" HorizontalAlignment="Left" Height="631" Margin="0,58,0,0" Grid.Row="1" VerticalAlignment="Top" Width="226"
ItemsSource="{Binding Path=Projects}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding ChildFolders}">
<StackPanel Orientation="Horizontal" >
<Image Source="{Binding Icon}" Margin="5, 5, 5, 5"></Image>
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" BorderThickness="0" FontSize="16" Margin="5" IsReadOnly="True" PreviewMouseDoubleClick="SelectAll" LostFocus="TextBoxLostFocus"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<Grid Grid.ColumnSpan="2" Grid.Column="4" HorizontalAlignment="Left" Height="631" Margin="245,58,0,0" Grid.Row="1" VerticalAlignment="Top" Width="540">
<ScrollViewer HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
<ListView x:Name="ProjectListView" Margin="0,0,10,0" ItemsSource="{Binding Projects}" FontSize="16" Foreground="Black">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="false">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
ANd heres my base View Model
private ObservableCollection<Project> projects;
public ObservableCollection<Project> Projects
{
get { return projects; }
set
{
if (value != projects)
{
projects = value;
OnPropertyChanged("Projects");
}
}
}
This is the Code Behind
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
MainViewModel model = new MainViewModel();
model.BuildData();
this.ProjectListView.ItemsSource = model.Projects;
}
private void FilterListView(object sender, TextChangedEventArgs e)
{
CollectionViewSource.GetDefaultView(this.ProjectListView.ItemsSource).Refresh();
}
FilterListView is the TextChange method. It breaks on the first line. ProjectListVIew is registering as null but it shouldn't even be launched because it is dependent on a change in the TextBox.
Edit. Here's the code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
MainViewModel model = new MainViewModel();
model.BuildData();
this.ProjectListView.ItemsSource = model.Projects;
}
private void FilterListView(object sender, TextChangedEventArgs e)
{
CollectionViewSource.GetDefaultView(this.ProjectListView.ItemsSource).Refresh();
}
private void SelectAll(object sender, MouseButtonEventArgs e)
{
TextBox box = sender as TextBox;
box.IsReadOnly = false;
box.SelectAll();
}
private void TextBoxLostFocus(object sender, RoutedEventArgs e)
{
TextBox box = sender as TextBox;
box.IsReadOnly = true;
}
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
TextBox tb = (TextBox)sender;
tb.Text = string.Empty;
tb.Foreground = Brushes.Black;
tb.GotFocus -= TextBox_GotFocus;
}
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
TextBox box = (TextBox)sender;
box.Text = "Search Projects";
box.Foreground = Brushes.LightGray;
box.GotFocus += TextBox_GotFocus;
}
}
}
Base View Model
public class ViewModelBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string projectName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(projectName));
}
}
#endregion INotifyPropertyChanged
}
And the View Model I am using
class MainViewModel : ViewModelBase
{
private ObservableCollection<Project> projects;
public ObservableCollection<Project> Projects
{
get { return projects; }
set
{
if (value != projects)
{
projects = value;
OnPropertyChanged("Projects");
}
}
}
EDIT:
My ListView constantly changes - as in, the data shown will be based on a User's selection in a TreeView. Right now, my filter doesn't take into consideration what is actually on the screen. It is only filtering based on the binded Collection.
So if my Collection is Fruit, Vegetables, Meat, Dairy and my ListView is Apple, Carrot, and Milk, if I search Apple, the ListView will be blank but if I search Fruit, I will have a populated row. Not correcty, clearly.
Sounds like I am fairly close.
This is my View Model:
public ICollectionView SourceCollection
{
get
{
return this.projectCollection.View;
}
}
public string FilterText
{
get
{
return filterText;
}
set
{
filterText = value;
this.projectCollection.View.Refresh();
RaisePropertyChanged("SearchProjectsText");
}
}
private void projectCollection_Filter(object sender, FilterEventArgs e)
{
if (string.IsNullOrEmpty(FilterText))
{
e.Accepted = true;
return;
}
Project project = e.Item as Project;
if (project.Name.ToUpper().Contains(FilterText.ToUpper()) || project.Path.ToUpper().Contains(FilterText.ToUpper()))
{
e.Accepted = true;
}
else
{
e.Accepted = false;
}
}
public void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Where SearchProjectText is the actual TextBox used for filtering. My relevant XAML:
<TextBox x:Name="SearchProjectsBox" Grid.Column="5" Background="White" Grid.Row="1" Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}"
Margin="47.333,0,0,654.333" VerticalContentAlignment="Center" Foreground="Black" Padding="6" FontSize="16" HorizontalAlignment="Left" Width="268"/>
<TreeView x:Name="Hierarchy" Grid.Column="4" HorizontalAlignment="Left" Height="631" Margin="0,58,0,0" Grid.Row="1" VerticalAlignment="Top" Width="226"
ItemsSource="{Binding Path=Projects}">
<ListView x:Name="ProjectListView" Margin="0,0,10,0" ItemsSource="{Binding SourceCollection}" FontSize="16" Foreground="Black">
MainViewModel
butviewModel.Projects
may still benull
? – AJ X.