UserControl
<UserControl x:Class="NolowaFrontend.Views.MainViews.SearchView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:NolowaFrontend.Views.MainViews"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
xmlns:designTime="clr-namespace:NolowaFrontend.Views"
mc:Ignorable="d" Name="_this"
d:DesignHeight="300" d:DesignWidth="350" d:Background="White">
<Grid>
<TextBlock Text="{Binding SearchedUsers.Count, diag:PresentationTraceSources.TraceLevel=High}" Foreground="Red" FontSize="20"/>
</Grid>
</UserControl>
CodeBehind
public partial class SearchView : UserControl
{
private readonly SearchVM _searchVM;
public SearchView(User user)
{
InitializeComponent();
_searchVM = new SearchVM(user); ;
DataContext = _searchVM;
}
public void TimerSearch(string text)
{
_searchVM.TimerSearch(text);
}
}
ViewModel
public class SearchVM : ViewModelBase
{
private readonly User _user;
private readonly ISearchService _searchService;
private ObservableCollection<SearchedUser> _searchedUsers = new ObservableCollection<SearchedUser>();
public ObservableCollection<SearchedUser> SearchedUsers
{
get { return _searchedUsers; }
set { _searchedUsers = value; OnPropertyChanged(); }
}
public SearchVM(User user)
{
_user = user;
_searchService = new SearchService();
}
public async void TimerSearch(string text)
{
var response = await _searchService.SearchUser(text);
var data = response.ResponseData;
SearchedUsers = data.ToObservableCollection();
}
}
bindig log
System.Windows.Data Warning: 67 : BindingExpression (hash=11842506): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=11842506): Found data context element: TextBlock (hash=56511253) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=11842506): Activate with root item SearchVM (hash=52539597)
System.Windows.Data Warning: 108 : BindingExpression (hash=11842506): At level 0 - for SearchVM.SearchedUsers found accessor RuntimePropertyInfo(SearchedUsers)
System.Windows.Data Warning: 104 : BindingExpression (hash=11842506): Replace item at level 0 with SearchVM (hash=52539597), using accessor RuntimePropertyInfo(SearchedUsers)
System.Windows.Data Warning: 101 : BindingExpression (hash=11842506): GetValue at level 0 from SearchVM (hash=52539597) using RuntimePropertyInfo(SearchedUsers): ObservableCollection`1 (hash=49313939 Count=0)
System.Windows.Data Warning: 108 : BindingExpression (hash=11842506): At level 1 - for ObservableCollection`1.Count found accessor RuntimePropertyInfo(Count)
System.Windows.Data Warning: 104 : BindingExpression (hash=11842506): Replace item at level 1 with ObservableCollection`1 (hash=49313939 Count=0), using accessor RuntimePropertyInfo(Count)
System.Windows.Data Warning: 101 : BindingExpression (hash=11842506): GetValue at level 1 from ObservableCollection`1 (hash=49313939 Count=0) using RuntimePropertyInfo(Count): '0'
System.Windows.Data Warning: 80 : BindingExpression (hash=11842506): TransferValue - got raw value '0'
System.Windows.Data Warning: 84 : BindingExpression (hash=11842506): TransferValue - implicit converter produced '0'
System.Windows.Data Warning: 89 : BindingExpression (hash=11842506): TransferValue - using final value '0'
System.Windows.Data Warning: 56 : Created BindingExpression (hash=29516363) for Binding (hash=55475379) BindingExpression:Path=SearchedUsers.Count; DataItem=null;
System.Windows.Data Warning: 58 : Path: 'SearchedUsers.Count'
System.Windows.Data Warning: 60 : BindingExpression (hash=29516363): Default mode resolved to OneWay
System.Windows.Data Warning: 61 : BindingExpression (hash=29516363): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 62 : BindingExpression (hash=29516363): Attach to System.Windows.Controls.TextBlock.Text (hash=35990092)
System.Windows.Data Warning: 67 : BindingExpression (hash=29516363): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=29516363): Found data context element: TextBlock (hash=35990092) (OK)
System.Windows.Data Warning: 71 : BindingExpression (hash=29516363): DataContext is null
System.Windows.Data Warning: 65 : BindingExpression (hash=29516363): Resolve source deferred
System.Windows.Data Warning: 67 : BindingExpression (hash=29516363): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=29516363): Found data context element: TextBlock (hash=35990092) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=29516363): Activate with root item SearchVM (hash=64320678)
System.Windows.Data Warning: 107 : BindingExpression (hash=29516363): At level 0 using cached accessor for SearchVM.SearchedUsers: RuntimePropertyInfo(SearchedUsers)
System.Windows.Data Warning: 104 : BindingExpression (hash=29516363): Replace item at level 0 with SearchVM (hash=64320678), using accessor RuntimePropertyInfo(SearchedUsers)
System.Windows.Data Warning: 101 : BindingExpression (hash=29516363): GetValue at level 0 from SearchVM (hash=64320678) using RuntimePropertyInfo(SearchedUsers): ObservableCollection`1 (hash=42592467 Count=0)
System.Windows.Data Warning: 107 : BindingExpression (hash=29516363): At level 1 using cached accessor for ObservableCollection`1.Count: RuntimePropertyInfo(Count)
System.Windows.Data Warning: 104 : BindingExpression (hash=29516363): Replace item at level 1 with ObservableCollection`1 (hash=42592467 Count=0), using accessor RuntimePropertyInfo(Count)
System.Windows.Data Warning: 101 : BindingExpression (hash=29516363): GetValue at level 1 from ObservableCollection`1 (hash=42592467 Count=0) using RuntimePropertyInfo(Count): '0'
System.Windows.Data Warning: 80 : BindingExpression (hash=29516363): TransferValue - got raw value '0'
System.Windows.Data Warning: 84 : BindingExpression (hash=29516363): TransferValue - implicit converter produced '0'
System.Windows.Data Warning: 89 : BindingExpression (hash=29516363): TransferValue - using final value '0'
System.Windows.Data Warning: 95 : BindingExpression (hash=11842506): Got PropertyChanged event from SearchVM (hash=52539597)
System.Windows.Data Warning: 101 : BindingExpression (hash=11842506): GetValue at level 0 from SearchVM (hash=52539597) using RuntimePropertyInfo(SearchedUsers): ObservableCollection`1 (hash=53428882 Count=2)
System.Windows.Data Warning: 105 : BindingExpression (hash=11842506): Item at level 1 has same type - reuse accessor RuntimePropertyInfo(Count)
System.Windows.Data Warning: 104 : BindingExpression (hash=11842506): Replace item at level 1 with ObservableCollection`1 (hash=53428882 Count=2), using accessor RuntimePropertyInfo(Count)
System.Windows.Data Warning: 101 : BindingExpression (hash=11842506): GetValue at level 1 from ObservableCollection`1 (hash=53428882 Count=2) using RuntimePropertyInfo(Count): '2'
System.Windows.Data Warning: 80 : BindingExpression (hash=11842506): TransferValue - got raw value '2'
System.Windows.Data Warning: 84 : BindingExpression (hash=11842506): TransferValue - implicit converter produced '2'
System.Windows.Data Warning: 89 : BindingExpression (hash=11842506): TransferValue - using final value '2'
Hi! When if there is a function that calls SearchView.TimerSearch("x")
I think UserControl shows the count that is returned from SearchView.TimerSearch("x")
But it's not work how I expect.
binding log says it changed to 2. but it shows '0' and never changed!
Can someone help me?
CodePudding user response:
You are binding to the nested Count
property of the collection. But since you are replacing the complete collection, the Count
property effectively does not change as the collection instance change is not detected by the Binding
. In other words, the Binding
is listening for a Count
changed event, but this event is never raised, because the collection instance itself has changed instead.
It's generally recommended to always use the same collection instance in a data binding context: clear the collection and add the new range of items.
Next is your async method TimerSearch
: it is currently not awaited and does not return a Task
!
Remember: async void
is only allowed for event handlers. Otherwise, a void
method must always be converted to return Task
.
When you await
a method you must await
the complete call tree (all the callers too): async Task
everywhere.
// Make method return Task
public async Task TimerSearchAsync(string text)
{
var response = await _searchService.SearchUser(text);
SearchedUsers.Clear();
foreach (var data in response.ResponseData)
{
SearchedUsers.Add(data);
}
}
In case response.ResponseData
returns a List<T>
, you can replace the foreach
loop with a call of the List<T>.ForEach
method to compact the code:
response.ResponseData.ForEach(SearchedUsers.Add);
Next, convert the calling method to return a Task
too and await
the TimerSearch
method call:
// Declare method async and return a Task
public async Task TimerSearcAsynch(string text)
{
await _searchVM.TimerSearchAsync(text);
}
Finally, avoid setting the DataContext
in your control. This limits the usability of the control to be only used in the special context.
Generally, you don't have a view model class for each control, this is not how you design controls. Controls must be developed independent from a view model class.
In your case, the control would have a UserCount
dependency property, which you later can bind to an external view model. Internally, the TextBox
would bind to the UserCount
dependency property.