簡體   English   中英

為什么ListView中的此DataTemplate無法自動更新其綁定?

[英]Why is this DataTemplate inside a ListView not updating its binding automatically?

我具有以下類層次結構:

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 (我可以使用斷點進行驗證),但是列表視圖不會相應更新(我希望0更改為1,但對於Mid特定實例,不會再次調用該轉換器。

為什么此更改不會觸發GUI的更新?

我知道我可以通過一些技巧來解決此問題(例如,將數據上下文設置為null並返回,或者可以通過使用依賴項屬性來調用顯式更新),但是我有兩個原因想要避免這種情況:

  • 我的實際代碼比此MCVE更復雜,並且看起來非常難看。
  • 我已經在所有(實際)類中添加了所有必需的ObservableCollectionINotifyPropertyChanged接口,正是這樣,我才不需要執行手動更新-所以我覺得在這種情況下應該進行自動更新,除非我已經錯過了一些東西。

您可以使用多重綁定:

<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

    ...
}

這樣,無論何時更新任何綁定,都將調用轉換器。

為什么此更改不會觸發GUI的更新?

因為綁定的源屬性( BotList )沒有更新。 僅在更新數據綁定屬性時才調用轉換器。

您可以使用@Sinatr建議的MultiBinding ,也可以

  • 直接綁定到集合的Count屬性:

     <TextBlock Text="{Binding BotList.Count}" /> 
  • Mid類中實現INotifyPropertyChanged接口,並在每次添加項目時引發BotList屬性的PropertyChanged事件。 處理CollectionChanged

您還可以將轉換邏輯移動到視圖模型,綁定到該模型的一個屬性,並在每次刷新綁定時都為其引發PropertyChanged

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM