ItemsControl内的元素不会更新,但ListBox内的元素会更新

(编辑整个帖子,因为你们认为正在进行一些代码魔术工作)

简介

我有一个 Observable Collection ,应该在列表中将其可视化

为此,我想使用 ItemsControl ,但是列表元素不会更新(它们为空或显示我定义的后备值)

当使用 ListBox代替它时,它可以按预期工作,但是随后我得到了我不想要的列表项选择。

TL; DR;问题

ItemsControl不会显示正确的值,但ListBox会显示正确的值。

要复制的代码

为重现该问题,我创建了一个新的WPF项目,以尽可能简单地显示问题,这是我的最小示例的完整代码

我有一个自定义UserControl,主要显示一些文本,在这种情况下为地址(当前)仅在构造函数中设置:

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Controls;

namespace WpfApp1
{
    public partial class MyUserControl : UserControl,INotifyPropertyChanged
    {
        private readonly string _address;

        public MyUserControl()
        {
            InitializeComponent();
        }

        public MyUserControl(string address)
        {
            InitializeComponent();
            _address = address;
            OnPropertyChanged(nameof(Address));
        }

        public string Address => _address;

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            this.PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));
        }

    }
}

这是用户控件的XAML代码:

<UserControl x:Class="WpfApp1.MyUserControl"
             <!-- snip namespaces --> 
             xmlns:local="clr-namespace:WpfApp1"
             mc:Ignorable="d" 
             d:DesignHeight="20" d:DesignWidth="300">
    <Border BorderBrush="Black" BorderThickness="0.6">
        <Border.Style> <!-- snip --> </Border.Style>
        <StackPanel Orientation="Horizontal">
            <Label Grid.Column="0" Grid.Row="0" Padding="2" Content="Address:"/>
            <Label Grid.Column="1" Grid.Row="0" Padding="2" Grid.ColumnSpan="2" Content="{Binding Path=Address,FallbackValue=00000000000000000000000000000}"/>
        </StackPanel>
    </Border>
</UserControl>

主窗口的XAML现在使用相同的绑定以及其他方式呈现两个列表,一个ItemsControl和一个ListBox

<Window x:Class="WpfApp1.MainWindow"
       <!-- snip namespaces -->
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel x:Name="FeeKeyListView" VerticalAlignment="Top" HorizontalAlignment="Stretch" Margin="5">
            <ItemsControl ItemsSource="{Binding MyList,RelativeSource={RelativeSource FindAncestor,AncestorType=Window}}" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinHeight="200">
                <ItemsControl.ItemsPanel>
                    <itemspaneltemplate>
                        <StackPanel/>
                    </itemspaneltemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <local:MyUserControl/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
            <ListBox ItemsSource="{Binding MyList,AncestorType=Window}}" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinHeight="200">
                <ListBox.ItemsPanel>
                    <itemspaneltemplate>
                        <StackPanel/>
                    </itemspaneltemplate>
                </ListBox.ItemsPanel>
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <local:MyUserControl/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </StackPanel>
    </Grid>
</Window>

最后但并非最不重要的MainWindow类,其中包含“可观察”列表:

using System.Collections.ObjectModel;
using System.Windows;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {

        public ObservableCollection<MyUserControl> MyList { get; set; } = new ObservableCollection<MyUserControl>();

        public MainWindow()
        {
            InitializeComponent();

            MyList.Clear();
            MyList.Add(new MyUserControl("my address1"));
        }
    }
}

结果窗口显示,值正确绑定在ListBox中,但未正确绑定到ItemsControl中。

所需的行为是,ItemsControl会像ListBox一样显示“我的地址1”。

ItemsControl内的元素不会更新,但ListBox内的元素会更新

iCMS 回答:ItemsControl内的元素不会更新,但ListBox内的元素会更新

IsItemItsOwnContainerOverride中,ItemsControl方法的不同实现导致了不同的行为

protected virtual bool IsItemItsOwnContainerOverride(object item)
{
    return (item is UIElement);
}

ListBox

protected override bool IsItemItsOwnContainerOverride(object item)
{
    return (item is ListBoxItem);
}

当该方法对ItemsItemsSource集合中的某个项目返回true时(在您的UserControls的ItemsControl中也是如此),则不会生成任何项目容器,因此不会应用ItemTemplate。

但是,通常不会将UIElements的集合分配给ItemsSource属性,而是将视图模型项的集合分配给ItemTemplate中的元素绑定其属性。

本文链接:https://www.f2er.com/2081796.html

大家都在问