I can Bind an observablelist to datagrid in WPF, but I am losing Binding when adding a custom filtering functionality to Datagrid
I created a User Control which contains a DataGrid in WPF, the DataGrid is bound to variable “FilteredCollection”
public ObservableCollection<cs_Log> FilteredCollection
{
get { return _filteredcollection; }
set { _filteredcollection = value; OnPropertyChanged("FilteredCollection"); dgLogger.ItemsSource = _filteredcollection; }
}
When I call the following function, the data is copied and datagrid is showing the new added rows correctly
void ApplyFilter()
{
FilteredCollection = csGlobal.LogList;
}
later I added a checkbox for filtering and I bound it to variable “InfoInclude”, also I modified the function
public bool InfoInclude
{
get { return _infoinclude; }
set { _infoinclude = value; OnPropertyChanged("InfoInclude"); ApplyFilter(); }
}
void ApplyFilter()
{
ObservableCollection<cs_Log> TempCollection = new ObservableCollection<cs_Log>();
foreach (cs_Log item in csGlobal.LogList)
if (((item.sType == "Information") && InfoInclude) || ((item.sType == "Warning") && WarnInclude) || ((item.sType == "Error") && ErrInclude))
TempCollection.Add(item);
FilteredCollection = TempCollection;
//FilteredCollection = csGlobal.LogList;
}
the result was:
- When adding a new rows the “FilteredCollection” variable is already updated but the datagrid is not showing the new added rows
- the when checking/unchecking the checkbox, the datagrid show the filtered data on the datagrid
How can I have both adding and filtering functionality to work together as same time?
Thanks
MKamal is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
4
From your explanations I understood: the FilteredCollection
collection is loaded with a full collection of rows when the view starts; the InfoInclude, WarnInclude, ErrInclude properties are created only to manage filtering. If this is correct, then in my opinion, a more optimal implementation of filtering would be at the View level.
Look at this example (the code you didn’t show, I’m recreating it based on my guesses):
public class LogViewModel
{
private GlobalModel csGlobal = new();
public LogViewModel()
{
FilteredCollection = new(csGlobal.LogList);
}
public ObservableCollection<cs_Log> FilteredCollection { get; }
}
Window XAML:
<Window.DataContext>
<local:LogViewModel/>
</Window.DataContext>
<UniformGrid Columns="2">
<DataGrid x:Name="dgLog" Margin="10" ItemsSource="{Binding FilteredCollection}"/>
<UniformGrid Columns="1">
<CheckBox x:Name="InfoInclude"
Content="{Binding Name, RelativeSource={RelativeSource Self}}"
Click="OnRefreshFilter"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
<CheckBox x:Name="WarnInclude"
Content="{Binding Name, RelativeSource={RelativeSource Self}}"
Click="OnRefreshFilter"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
<CheckBox x:Name="ErrInclude"
Content="{Binding Name, RelativeSource={RelativeSource Self}}"
Click="OnRefreshFilter"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</UniformGrid>
</UniformGrid>
</Window>
Window Code Behind:
private void OnRefreshFilter(object sender, RoutedEventArgs e)
{
bool infoInclude = InfoInclude.IsChecked == true;
bool warnInclude = WarnInclude.IsChecked == true;
bool errInclude = ErrInclude.IsChecked == true;
dgLog.Items.Filter = item =>
{
cs_Log log = (cs_Log)item;
return log.sType switch
{
"Information" => infoInclude,
"Warning" => warnInclude,
"Error" => errInclude,
_ => false
};
};
}
P.S. And please note that binding is not just a “nice term”, but an instance of Binding
set, in this case, in the value of a property in XAML.