用户控件 UI 没有改变
Usercontrol UI doesn't change
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'
嗨!如果有函数调用 SearchView.TimerSearch("x")
我认为 UserControl 显示了从 SearchView.TimerSearch("x")
返回的计数
但它并不像我期望的那样工作。
绑定日志说它更改为 2。但它显示“0”并且从未更改过!
有人可以帮助我吗?
您正在绑定到集合的嵌套 Count
属性。但是由于您要替换整个集合,因此 Count
属性 实际上不会更改,因为 Binding
未检测到集合实例更改。换句话说,Binding
正在侦听 Count
已更改的事件,但此事件从未引发,因为集合实例本身已更改。
通常建议在数据绑定上下文中始终使用相同的集合实例:清除集合并添加新的项目范围。
接下来是您的异步方法 TimerSearch
:目前未等待并且不会 return Task
!
请记住:async void
仅 允许用于事件处理程序。否则,void
方法必须始终转换为 return Task
.
当您 await
一个方法时,您必须 await
完整的调用树(所有调用者也是如此):async Task
无处不在。
// 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);
}
}
如果 response.ResponseData
return 是 List<T>
,您可以将 foreach
循环替换为调用 List<T>.ForEach
方法来压缩代码:
response.ResponseData.ForEach(SearchedUsers.Add);
接下来,将调用方法也转换为return一个Task
和await
TimerSearch
方法调用:
// Declare method async and return a Task
public async Task TimerSearcAsynch(string text)
{
await _searchVM.TimerSearchAsync(text);
}
最后,避免在控件中设置 DataContext
。这将控件的可用性限制为仅在特殊上下文中使用。
通常,每个控件都没有视图模型 class,这不是您设计控件的方式。控件的开发必须独立于视图模型 class.
在您的情况下,该控件将具有 UserCount
依赖项 属性,您稍后可以将其绑定到外部视图模型。在内部,TextBox
将绑定到 UserCount
依赖项 属性.
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'
嗨!如果有函数调用 SearchView.TimerSearch("x")
我认为 UserControl 显示了从 SearchView.TimerSearch("x")
返回的计数但它并不像我期望的那样工作。
绑定日志说它更改为 2。但它显示“0”并且从未更改过!
有人可以帮助我吗?
您正在绑定到集合的嵌套 Count
属性。但是由于您要替换整个集合,因此 Count
属性 实际上不会更改,因为 Binding
未检测到集合实例更改。换句话说,Binding
正在侦听 Count
已更改的事件,但此事件从未引发,因为集合实例本身已更改。
通常建议在数据绑定上下文中始终使用相同的集合实例:清除集合并添加新的项目范围。
接下来是您的异步方法 TimerSearch
:目前未等待并且不会 return Task
!
请记住:async void
仅 允许用于事件处理程序。否则,void
方法必须始终转换为 return Task
.
当您 await
一个方法时,您必须 await
完整的调用树(所有调用者也是如此):async Task
无处不在。
// 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);
}
}
如果 response.ResponseData
return 是 List<T>
,您可以将 foreach
循环替换为调用 List<T>.ForEach
方法来压缩代码:
response.ResponseData.ForEach(SearchedUsers.Add);
接下来,将调用方法也转换为return一个Task
和await
TimerSearch
方法调用:
// Declare method async and return a Task
public async Task TimerSearcAsynch(string text)
{
await _searchVM.TimerSearchAsync(text);
}
最后,避免在控件中设置 DataContext
。这将控件的可用性限制为仅在特殊上下文中使用。
通常,每个控件都没有视图模型 class,这不是您设计控件的方式。控件的开发必须独立于视图模型 class.
在您的情况下,该控件将具有 UserCount
依赖项 属性,您稍后可以将其绑定到外部视图模型。在内部,TextBox
将绑定到 UserCount
依赖项 属性.