为什么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}" /> 

  • 实现在MidINotifyPropertyChanged接口并在每次向其中添加项目时提高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

回到顶部