为什么ListView中的DataTemplate不会自动更新其绑定?
我有以下的类层次结构:为什么ListView中的DataTemplate不会自动更新其绑定?
namespace WpfBindingProblem {
public class Top
{
public IList<Mid> MidList { get; } = new ObservableCollection<Mid>();
}
public class Mid
{
public IList<Bot> BotList { get; } = new ObservableCollection<Bot>();
}
public class Bot
{
}
}
而且我有这样的XAML窗口:
<Window x:Class="WpfBindingProblem.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfBindingProblem"
mc:Ignorable="d"
Title="MainWindow" Height="217.267" Width="333.686">
<Window.DataContext>
<local:Top/>
</Window.DataContext>
<Window.Resources>
<local:TriggersToString x:Key="TriggersToString"/>
</Window.Resources>
<Grid>
<ListView Margin="10" ItemsSource="{Binding MidList}" x:Name="ThatList">
<ListView.Resources>
<DataTemplate DataType="{x:Type local:Mid}">
<TextBlock Text="{Binding BotList, Converter={StaticResource TriggersToString}}" />
</DataTemplate>
</ListView.Resources>
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Add mid" Click="AddMid"/>
<MenuItem Header="Add bot to selected mid" Click="AddBot" />
</ContextMenu>
</ListView.ContextMenu>
<ListView.View>
<GridView>
<GridViewColumn/>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
有了这些处理程序:
namespace WpfBindingProblem {
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void AddMid(object sender, RoutedEventArgs e)
{
if(DataContext is Top p)
{
p.MidList.Add(new Mid());
}
}
private void AddBot(object sender, RoutedEventArgs e)
{
if(ThatList.SelectedItem is Mid c)
{
c.BotList.Add(new Bot());
}
}
}
}
而这种转换器(作为一个替身适用于任意转换器):
namespace WpfBindingProblem {
[ValueConversion(typeof(IList<Bot>), typeof(string))]
public class TriggersToString : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is IList<Bot> list)
{
return list.Count.ToString();
}
throw new InvalidOperationException();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException();
}
}
}
在出现,当我们运行这个例子,我可以右击并选择“添加中旬”这样的Mid
一个实例添加到Top
数据上下文和列表视图相应更新,显示窗口号码0(如变换逻辑)
然而,当我点击“添加漫游器来选择中间”,的Bot
一个实例被添加到所选择的Mid
(I可以验证这一点使用断点),但是列表视图是没有相应的更新(我预计0改为1,但转换器不为Mid
特定情况下再次调用)。
为什么会发生这种变化不会触发GUI的更新?
我知道我可以通过一些窍门解决这个问题(比如将数据上下文设置为null
并返回,或者可能通过使用依赖属性调用显式更新),但有两个原因可以避免这种情况:
- 我的实际代码比这个MCVE更复杂,它看起来非常难看。
- 我已经为所有需要的
ObservableCollection
s和INotifyPropertyChanged
接口洒满了所有我的(实际)类,这样我就不需要执行手动更新了 - 所以我觉得在这种情况下应该会发生自动更新,除非我错过了一些东西。
回答:
为什么会发生这种变化不会触发GUI的更新?
因为绑定的源属性(BotList
)没有更新。只有当绑定的属性数据更新的转换器被调用。
你可以使用一个MultiBinding
通过@Sinatr的建议,或者你可以
直接绑定到集合的
Count
属性:<TextBlock Text="{Binding BotList.Count}" />
实现在
Mid
类INotifyPropertyChanged
接口并在每次向其中添加项目时提高BotList
属性的PropertyChanged
事件。处理CollectionChanged
。
您也可以将您的转换逻辑视图模型,结合这一个的属性,也提高PropertyChanged
它,只要你想要的结合被刷新。
回答:
您可以使用多绑定:
<TextBlock> <TextBlock.Text>
<MultiBinding Converter="{StaticResource TriggersToString}">
<Binding Path="BotList" />
<Binding Path="BotList.Count" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
和多值转换器:
public class TriggersToString : IMultiValueConverter {
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) =>
(values[0] as IList<Bot>)?.Count.ToString(); // first binding
...
}
这样,每当任何绑定更新的转换器被调用。
以上是 为什么ListView中的DataTemplate不会自动更新其绑定? 的全部内容, 来源链接: utcz.com/qa/263225.html