Filter observablecollection (mvvm) [duplicate] - wpf

This question already has answers here:
Filter an observable collection
(3 answers)
Closed 4 years ago.
I've got an ObservableCollection(Of PdfMarkupAnnotationDataWrapper) which is bound to a ListBoxEdit. In addition I've got a textbox which should work as a filter.
Now when the user types something in the textbox the ObservableCollection in my Viewmodel should be filtered by the input of the textbox.
Here is my collection
Private Property _annotationList As ObservableCollection(Of PdfMarkupAnnotationDataWrapper)
Public Property AnnotationList As ObservableCollection(Of
PdfMarkupAnnotationDataWrapper)
Get
Return _annotationList
End Get
Set(value As ObservableCollection(Of PdfMarkupAnnotationDataWrapper))
_annotationList = value
OnPropertyChanged()
End Set
End Property
Is there any way to accomplish this task?
I was thinking about copying the collection but there has to be better solution.

I was thinking about copying the collection but there has to be better solution.
That would be to remove or add items from it. But you still need to store the original unfiltered items in another collection.
You could use LINQ to do the filtering, e.g.:
Private _unFilteredAnnotationList As ObservableCollection(Of PdfMarkupAnnotationDataWrapper) 'make sure to populate this one
Private _annotationList As ObservableCollection(Of PdfMarkupAnnotationDataWrapper)
Public Property AnnotationList As ObservableCollection(Of PdfMarkupAnnotationDataWrapper)
Get
Return _annotationList
End Get
Set(value As ObservableCollection(Of PdfMarkupAnnotationDataWrapper))
_annotationList = value
OnPropertyChanged()
End Set
End Property
Private _text As String
Public Property Text As String
Get
Return _text
End Get
Set(value As String)
_text = value
OnPropertyChanged()
'filter
AnnotationList = New ObservableCollection(Of PdfMarkupAnnotationDataWrapper)(_unFilteredAnnotationList.Where(Function(x)
Return x.YourStringProperty.StartsWith(_text)
End Function))
End Set
End Property

Related

ListView with grouping and sorting not refresh while INotifyPropertyChanged used

I have my own class which uses INotifyPropertyChanged correctly (Raising updates events), but when a property of type DateTime updated and called (View.Run) the listView not updating untill another property changing (not this property)
Now with the code:
Public Class EntryInfo
Implements INotifyPropertyChanged
ReadOnly Property DateAccessed As Date
Get
.......
Return _Access
End Get
End Property
Readonly Property Property1 as object
Get
.......
Return _Property1
End Get
End Property
Friend Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
RaiseEvent ApropertyHasChanged()
End Sub
Then when I need to Change the "DateAccessProperty" I use this code:
Friend Sub SetAccessTime(Dt As Date)
_Access = Dt
NotifyPropertyChanged("DateAccessed")
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''
After this I have a ListView named "LV1"
Dim Coll as new observableCollection(Of EntryInfo)
....... filing "Coll" with items (EntryInfo)
Lv1.ItemsSource =Coll
Then I do the following:
Do some sort and group operations.
Changing "DateAccessed" value. so that the "ApropertyHasChanged" event fired and at this point I used the following code
Private Sub RefreshViewNow()
Dim _view As ListCollectionView = TryCast(CollectionViewSource.GetDefaultView(LV1.ItemsSource), ListCollectionView)
If _view IsNot Nothing Then _view.Refresh()
'\\\ Items.Refresh()
End Sub
But _view not refreshed.
But if the property "Property1" changed the _View refreshed.
Any help?
The solution is by set the following "_view" properties:
_view.IsLiveFiltering = True
_view.IsLiveGrouping = True
_view.IsLiveSorting = True
or at least one of them if you want one of them only to be activated.

Cascading Comboboxes WPF mvvm and EF

I'm trying to create cascading comboboxes on my view. I have a table, imported from sql with ADO.NET Entity Data Model:
Partial Public Class tbl_Activities
Public Property MRU As String
Public Property Market As String
Public Property Tower As String
Public Property FirstActivity As String
Public Property SecondActivity As String
First combobox should contain FirstActivity items and the second one SecondActivity items related to the first one.
I'm using method to populate the first one:
Public Sub FillFirstActivity()
Using context As New TimerConn
Dim result = (From act In context.tbl_Activities Where (act.MRU = MRU() And act.Market = MAR() And act.Tower = TOW()) Order By act.FirstActivity).Distinct().ToList()
For Each act In result
_First.Add(act)
Next
End Using
End Sub
Properties:
Public Property First() As ObservableCollection(Of tbl_Activities)
Get
Return _First
End Get
Set(value As ObservableCollection(Of tbl_Activities))
_First = value
End Set
End Property
Public Property Second() As ObservableCollection(Of tbl_Activities)
Get
Return _Second
End Get
Set(value As ObservableCollection(Of tbl_Activities))
_Second = value
End Set
End Property
Public Property SelectedFirst() As tbl_Activities
Get
Return _selectedFirst
End Get
Set(value As tbl_Activities)
_selectedFirst = value
Me.Second.Clear()
Me.Second.Add(_selectedFirst)
End Set
End Property
XAML:
<ComboBox ItemsSource="{Binding EmployeeViewM.First}" SelectedIndex="{Binding EmployeeViewM.SelectedFirst}" DisplayMemberPath="FirstActivity"/>
<ComboBox ItemsSource="{Binding EmployeeViewM.Second}" DisplayMemberPath="SecondActivity"/>
My problem
I'm not able to populate it correctly. In the first combobox I have doubles (Test1, Test2, Test2), and in the second combobox I get only item related to the item chosen from the first combobox:
First one should be distinct and the second one with all items for the current activity.
First Combobox = 'Test1', 'Test2'
Second Combobox = If 'Test1' then 'Test1Add', If 'Test2' then 'Test2Add', 'Test2Add1'
I don't know what I'm doing wrong here. Maybe I should split it into Two tables with PK - FK and then try? If so, how can I bind it to the comboboxes?
My Table view:
Thank you very much for any suggestion.

Model - ViewModel sync and filtered ObservableCollections

I am working with EF and MVVM.
My Model contains this:
Public Property Visits As DbSet(Of Visit)
The Visit class implements INotifyPropertyChanged and its properties properly raise PropertyChanged events.
My ViewModel contains these properties, used for my views binding (context is my model):
Private _BareVisits As ObservableCollection(Of Visit)
Public Property BareVisits As ObservableCollection(Of Visit)
Get
If _BareVisits Is Nothing Then
_BareVisits = New ObservableCollection(Of Visit)(context.Visits)
AddHandler _BareVisits.CollectionChanged, AddressOf BareVisits_CollectionChanged
End If
Return _BareVisits
End Get
Set(value As ObservableCollection(Of Visit))
_BareVisits = value
End Set
End Property
Private _Visits As ObservableCollection(Of Visit)
Public Property Visits As ObservableCollection(Of Visit)
Get
If _Visits Is Nothing Then
_Visits = New ObservableCollection(Of Visit)(
BareVisits.Where(
Function(V) Not V.IsMediGenerated AndAlso V.IsHistoryParseComplete
)
)
End If
Return _Visits
End Get
Set(value As ObservableCollection(Of Visit))
_Visits = value
End Set
End Property
Private Sub BareVisits_CollectionChanged(sender As Object, e As NotifyCollectionChangedEventArgs)
Select Case e.Action
Case NotifyCollectionChangedAction.Add
context.Visits.AddRange(e.NewItems.OfType(Of Visit))
context.SaveChanges()
Case NotifyCollectionChangedAction.Remove
context.Visits.RemoveRange(e.OldItems.OfType(Of Visit))
context.SaveChanges()
Case Else
Exit Sub
End Select
End Sub
As you see, the BareVisits property is just the DB collection of my Visits.
The Visits property (the one my view is bound to) depends on BareVisits to return filtered records.
Questions:
1) Which is the best method to save a new visit? By using the event handler posted? Or should I talk to the Model directly and somehow bubble this changes to the ViewModel? If I hook the CollectionChanged handler to the Visits property, do I need this BareVisits property at all?
2) Suppose the changes take place in the Model itself, I suppose I should also perform the record adds / delete to the BareVisits property also. What happens to the Visits property? (the filtered one) I have tried everything and its CollectionChanged event is never fired. Should I tamper with it also by hand?
I just want my view to depict the data changes and I am at a loss.
EDIT: I have also tried to use ICollectionView to filter the raw data (instead of a new ObservableCollection property) but it is not a choice since the data in my datagrid is rendered un-editable this way.
Thank you in advance. Any help will be greatly appreciated.

WPF INotifyPropertyChanged not allowing null value

Using WPF and EF and new to both. I may use the wrong terminology.
Using the EF wizard and code generators, I set up an EF using several tables, one of which is a lookup table.
I set up a form with a datagrid for the user to edit items in this lookup table. An issue I'm having is that the user can edit a cell, then close the form, but the editing of the cell will not update the underlying SQL database. I researched INotifyPropertyChanged and it seemed to be what I needed.
I implemented INotifyPropertyChanged to class bound to the datagrid. Before the implementation, the datagrid displayed all null values. After implementation, a message displays when the first null value is read that a nullable object must have a value.
Code:
Public Property ProcedureName As String
Get
Return _ProcedureName
End Get
Set(value As String)
_ProcedureName = value
RaisePropertyChanged("ProcedureName")
End Set
End Property
Private _ProcedureName As String
The exception occurs at "_ProcedureName = value".
Entire class:
Imports System
Imports System.Collections.ObjectModel
Partial Public Class tlkpProcedures_PartB
Inherits PropertyChangedBase
Public Property CPT As String
Get
Return _CPT
End Get
Set(value As String)
_CPT = value
RaisePropertyChanged("CPT")
End Set
End Property
Private _CPT As String
Public Property ProcedureName As String
Get
Return _ProcedureName
End Get
Set(value As String)
_ProcedureName = value
RaisePropertyChanged("ProcedureName")
End Set
End Property
Private _ProcedureName As String
Public Property BillingAmount As Nullable(Of Decimal)
Get
Return _BillingAmount
End Get
Set(value As Nullable(Of Decimal))
_BillingAmount = value
RaisePropertyChanged("BillingAmount")
End Set
End Property
Private _BillingAmount As Decimal
Public Property UniqueID As Integer
Public Overridable Property tblBilling_PartB As ObservableCollection(Of tblBilling_PartB) = New ObservableCollection(Of tblBilling_PartB)
End Class
Any help or advice is appreciated.
I'm not very good at VB but it seems like you try to assign a Nullable ( value As Nullable(Of Decimal) ) to a non-nullable (Private _BillingAmount As Decimal).
You should either cast value as Decimal or define _BillingAmount as Nullable(Of Decimal).

Create A WPF ObservableCollection From A SubSonic 2.2 Collection

If I have a DAL created by SubSonic 2.2, how do I convert the Collections created by it to WPF ObservableCollections in code (pref.VB.NET) to be consumed by WPF?
Sorry !VB:
[Test]
public void Exec_Testing()
{
ProductCollection products =
DB.Select().From("Products")
.Where("categoryID").IsEqualTo(5)
.And("productid").IsGreaterThan(50)
.ExecuteAsCollection<ProductCollection>();
Assert.IsTrue(products.Count == 77);
ObservableCollection<Product> obsProducts = new ObservableCollection<Product>(products);
}
You would have to manually add this to your DAL classes, but it's not too hard. In the top of each data access layer class, add "Implements INotifyPropertyChanged" and then in each property, add the code in the "set" like you see below.
Private _Book As String
Public Property Book() As String
Get
Return _Book
End Get
Set(ByVal value As String)
If Not _Book = value Then
_Book = value
' Raise the property changed event.
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Book"))
End If
End Set
End Property
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

Resources