I would like to train in c# and I created a WPF project in which are displayed some persons(with each a name and a work), and by selecting a field ('name' or 'work') and a search string, I would get all the persons filtered. for example, the field is 'name', the string is 'tin' and the only person whose name contains 'tin' is 'tintin'. I wrote all the program but I get a null reference error with the search engine(the parameterized class whose purpose is to filter the persons).
here is the person class:
namespace VueEnPremier.Model
{
public class Person : ViewModelBase
{
public string Name { get; set; }
public string Work { get; set; }
}
}
here is my view:
<Window
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:VueEnPremier"
xmlns:vm="clr-namespace:VueEnPremier.ViewModel"
xmlns:System="clr-namespace:System;assembly=mscorlib" x:Class="VueEnPremier.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<!--<vm:VMSearchName x:Key="ByName" />
<vm:VMSearchWork x:Key="ByWork"/>-->
<vm:VMSearch x:Key="ByName" NameOfTypeToSearch="Name"/>
<vm:VMSearch x:Key="ByWork" NameOfTypeToSearch="Work"/>
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource Locator}}">
<StackPanel>
<StackPanel x:Name="liste">
<ComboBox x:Name="comboBox" Width="150" HorizontalAlignment="Left" Margin="10,10,0,10"
SelectedItem="{Binding Main.SearchEngine, Mode=OneWayToSource}">
<ComboBoxItem Content="{StaticResource ByName}" HorizontalAlignment="Center" IsSelected="True"/>
<ComboBoxItem Content="{StaticResource ByWork}" HorizontalAlignment="Center"/>
</ComboBox>
<TextBox Text="{Binding Main.ToFind, Mode=OneWayToSource}"></TextBox>
<ItemsControl
ItemsSource="{Binding ElementName=comboBox,Path=SelectedItem.(vm:VMSearch.PersonsFiltered)}"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
here is my search engine:
namespace VueEnPremier.ViewModel
{
public class VMSearch : ViewModelBase
{
public string ToFind { get; set; }
public string NameOfTypeToSearch { get; set; }
public VMSearch(string nameOfTypeToSearch)
{
NameOfTypeToSearch = nameOfTypeToSearch;
}
public VMSearch() { }
protected List<Person> Persons { set; get; }
public void UpdatesDatas(List<Person> persons, string toFind)
{
Persons = persons;
ToFind = toFind;
RaisePropertyChanged(() => this.PersonsFiltered);
}
public override string ToString() => NameOfTypeToSearch;
public List<Person> PersonsFiltered
{
get
{
return Persons?.Where(c => (c.GetType().GetProperty(NameOfTypeToSearch).GetValue(c,null) as string).Contains(ToFind)).ToList();
}
}
}
}
The getter of PersonsFiltered is a little tricky, it gets the value of a property from the string name of this property ("Name" --> c.Name is obtained). The point is that in XAML, the combobox contains directly the 2 search engines, and the selectedItem property should be binded (one way to source) to the SearchEngine property of the viewmodel: all the logic stands in the bindings.
and finally here is my viewmodel:
using System.Collections.Generic;
using System.Windows.Documents;
using System.Windows.Media.Animation;
using GalaSoft.MvvmLight;
using VueEnPremier.Model;
namespace VueEnPremier.ViewModel
{
/// <summary>
/// This class contains properties that the main View can data bind to.
/// <para>
/// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
/// </para>
/// <para>
/// You can also use Blend to data bind with the tool's support.
/// </para>
/// <para>
/// See http://www.galasoft.ch/mvvm
/// </para>
/// </summary>
public class MainViewModel : ViewModelBase
{
public List<Person> AllNames { get; set; }
#region ToFind
private string _toFind = string.Empty;
public string ToFind
{
get => _toFind;
set
{
_toFind = value;
RaisePropertyChanged(()=>this.ToFind);
SearchEngine.UpdatesDatas(AllNames,value);
}
}
#endregion
#region SearchEngine
private VMSearch _searchEngine;
public VMSearch SearchEngine
{
get { return _searchEngine; }
set
{
if (value != _searchEngine)
_searchEngine = value;
RaisePropertyChanged("SearchEngine");
}
}
#endregion
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
////if (IsInDesignMode)
////{
//// // Code runs in Blend --> create design time data.
////}
////else
////{
//// // Code runs "for real"
////}
Fill();
}
private void Fill()
{
AllNames = new List<Person>();
AllNames.Add(new Person() {Name = "sanzot", Work = "boucher"});
AllNames.Add(new Person() {Name = "buck dany", Work = "pilote"});
AllNames.Add(new Person() {Name = "lefuneste", Work = "cuistre"});
AllNames.Add(new Person() {Name = "tintin", Work = "reporter"});
AllNames.Add(new Person() {Name = "blake", Work = "pilote"});
}
}
}
I use MVVM light. The error I get is, at startup :
System.NullReferenceException HResult=0x80004003 Message=La référence d'objet n'est pas définie à une instance d'un objet.
Source=VueEnPremier Arborescence des appels de procédure : à VueEnPremier.ViewModel.MainViewModel.set_ToFind(String value) dans C:\Users\osain\source\repos\MVVMBook\VueEnPremier\ViewModel\MainViewModel.cs :ligne 38
it says that in the line with 'searchEngine.updateDatas(AllNames,value);' the searchEngine variable is null.
thank you.
User contributions licensed under CC BY-SA 3.0