I am "attempting" to learn the MvvM architecture using C# within a WPF application. I quickly realized that I was writing a tonne of duplication boilerplate thus I decided to install the NuGet CoummunityToolkit.Mvvm to handle the vast majority for me.
I then started to create a very simple application which would just display items for me to learn the basics of MvvM. Therefore my View looks like such...
<UserControl.DataContext>
<viewmodel:DrawingMenuViewModel/>
</UserControl.DataContext>
<StackPanel>
<TextBox Text="{Binding SearchFilter}"/>
<DataGrid x:Name="ContactsResult"
ItemsSource="{Binding DrawingsCollectionView}"
SelectedItem="{Binding SelectedModel}"
AutoGenerateColumns="False" CanUserAddRows="False"
IsReadOnly="True" Height="300">
<DataGrid.Columns>
<DataGridTextColumn Header="DRAWING NO"
Binding="{Binding Path = DNumber}"/>
<DataGridTextColumn Header="DESCRIPTION"
Binding="{Binding Path = Description}"
Width="*"/>
<DataGridTextColumn Header="REV"
Binding="{Binding Path = Revision}"
Width="200"/>
</DataGrid.Columns>
</DataGrid>
<Button Content="Click" Command="{Binding OpenDrawingCommand}"/>
</StackPanel>
Then I started to rig up the backend ViewModel which works perfectly so far...
public partial class DrawingMenuViewModel : ObservableObject
{
public ObservableCollection<DrawingModel> _Drawings;
[ObservableProperty] ICollectionView drawingsCollectionView;
[ObservableProperty] DrawingModel selectedModel;
[ObservableProperty] string searchFilter = "D";
public DrawingMenuViewModel() => PopulateDatagrid();
#region Populating DataGrid
public void PopulateDatagrid()
{
// Initialize Data into the DataGrid Control
List<DrawingModel> testD = new List<DrawingModel>
{
new DrawingModel { DNumber = "D1294", Description = "Test 1", Revision = "A"},
new DrawingModel { DNumber = "D1295", Description = "Test 2", Revision = "A"},
new DrawingModel { DNumber = "D1296", Description = "Test 3", Revision = "A"},
new DrawingModel { DNumber = "D1297", Description = "Test 4", Revision = "A"},
};
// Hook-up data to view and set filter for search capability
_Drawings = new ObservableCollection<DrawingModel>(testD);
DrawingsCollectionView = CollectionViewSource.GetDefaultView(_Drawings);
DrawingsCollectionView.Filter = FilterDatagrid;
}
private bool FilterDatagrid(object obj)
{
if (obj is DrawingModel d)
{
return d.DNumber.Contains(searchFilter, StringComparison.OrdinalIgnoreCase) ||
d.Description.Contains(searchFilter, StringComparison.OrdinalIgnoreCase) ||
d.Revision.Contains(searchFilter, StringComparison.OrdinalIgnoreCase);
}
return false;
}
#endregion
[ICommand]
async Task OpenDrawing()
{
if (SelectedModel != null)
{
MessageBox.Show(SelectedModel.DNumber);
}
}
}
Where my issues begin is that I am struggling to understand how I can rig events such as a TextChanged event from the SearchFilter textbox which would run a command to filter the datagridview using the following statement...
CollectionViewSource.GetDefaultView(DrawingsCollectionView).Refresh();
What I have tried without success is something like...
<TextBox Text="{Binding SearchFilter}" TextChanged="{Binding OpenDrawingCommand}"/>
Which results in error XLS0523 "Event 'TextChanged' can only be bound to properties of delegate type 'TextChangedEventHandler'.". So I attempted to try calling the event like so...
XAML
<TextBox Text="{Binding SearchFilter}" TextChanged="{Binding OpenDrawing}"/>
C#
public void OpenDrawing(object sender, TextChangedEventArgs e)
{
CollectionViewSource.GetDefaultView(DrawingsCollectionView).Refresh();
}
Resulting in the following error...
System.Windows.Markup.XamlParseException: ''Provide value on 'System.Windows.Data.Binding' threw an exception.' Line number '15' and line position '48'.'