ItemsControl ItemSsource绑定不更新

问题描述 投票:0回答:3

我过去只是通过将字符串列表转换为带有换行符的一个字符串来创建一个文本块。这个Binding有效;它应该和所有人一起更新,但我正在尝试将文本列表移动到ItemsControl中,因为它们将来需要在某些时候成为超链接。问题:触发PropertyChangeEvent时,ItemsControl不会更改。相关守则如下:

XAML

<local:BaseUserControl x:Class="BAC.Windows.UI.Views.ErrorsView"
             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:BAC.Windows.UI.Views"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">

             ...

            <ItemsControl ItemsSource="{Binding Path=ErrorMessages}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding}"></TextBlock>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

            <!--<TextBlock VerticalAlignment="Center" Visibility="{Binding ErrorMessages, Converter={StaticResource VisibleWhenNotEmptyConverter}}" Text="{Binding ErrorMessages, Converter={StaticResource ErrorMessagesToTextConverter}}">

            (What I used to use)

            </TextBlock>-->


 ...

</local:BaseUserControl>

视图模型

using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using ASI.Core.Core;
using ASI.Core.DTO;
using ASI.Core.Extensions;
using ASI.Core.Mappers;
using BAC.Core.Resources;
using BAC.Core.Services;
using BAC.Core.ViewModels.Views; 

namespace BAC.Core.ViewModels
{
    public interface IErrorsViewModel : IViewModel<IErrorsView>
    {
    }

    public class ErrorsViewModel : BaseViewModel<IErrorsView>, IErrorsViewModel
    {
        ...

        private readonly ErrorDTO _errorDTO;
        private readonly ErrorDTO _warningDTO;

        public ErrorsViewModel(...) : base(view)
        {
            ...

            //Just added this string to know that it's at least binding. This Message displays, and never changes.
            ErrorMessages = new List<string>() {"Simple Message"};

            //Tells the View to bind dataContext to Viewmodel
            Edit();
        }

        private void errorDTOOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
        {
            ErrorDTO dto;
            if (!string.Equals(propertyChangedEventArgs.PropertyName, nameof(dto.HasError))) return;

            ErrorMessages.Clear();
            _errorDTO.ErrorMessages.Each(x => ErrorMessages.Add(Constants.Captions.Errors + ": " + x));
            _warningDTO.ErrorMessages.Each(x => ErrorMessages.Add(Constants.Captions.Warnings + ": " + x));

            OnPropertyChanged(() => ErrorMessages);
            OnPropertyChanged(() => HasError);
            OnPropertyChanged(() => HasWarning);
        }

        ...

        public bool HasError => _errorDTO.HasError;

        public bool HasWarning => _warningDTO.HasError;

        public IList<string> ErrorMessages { get; set; }

        ...
}

只是因为我知道人们可能会要求看到它......

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

      public void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression)
      {
         var body = propertyExpression.Body as MemberExpression;
         if (body != null)
            OnPropertyChanged(body.Member.Name);
      }

       protected void OnEvent(Action action)
       {
           try
           {
               action();
           }
           catch
           { }
       }
   }

我确信这是一件非常简单的事情,但是我看起来越难,我就越会被简单的事情所迷惑。除了ItemSource之外,为什么绑定适用于所有其他conrols?这有什么特别之处?

c# wpf
3个回答
1
投票

所以我能够通过使用ObservableCollection而不是List来使代码工作。 ObservableCollection在更改其集合时自动生成列表更改通知。以下是我的示例代码。我使用计时器每秒更新错误列表。

<Window x:Class="TestEer.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:TestEer"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
    <ItemsControl ItemsSource="{Binding Path=ErrorMessages}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

using System.Collections.ObjectModel;
using System.Timers;
using System.Windows;
using System.Windows.Data;

namespace TestEer
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    private Timer _timer;
    private readonly object _sync = new object( );
    public MainWindow( )
    {
        InitializeComponent( );
        BindingOperations.EnableCollectionSynchronization( ErrorMessages, _sync );
        _timer = new Timer
        {
            AutoReset = true,
            Interval = 1000
        };

        _timer.Elapsed += _timer_Elapsed;
        _timer.Enabled = true;
        _timer.Start( );
    }

    private void _timer_Elapsed( object sender, ElapsedEventArgs e )
    {
        ErrorMessages.Add( $"Error @ {e.SignalTime}" );
    }

    public ObservableCollection<string> ErrorMessages { get; } = new ObservableCollection<string>( );
}
}

2
投票

我还将添加另一个解释(即使我知道这是旧的)。

这不会更新属性的原因是List对象实际上没有更改,因此ListView不会更新列表。不使用“ObservableCollection”的唯一方法是在每个属性更改上创建一个全新的列表,如下所示:

    private void errorDTOOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
    {
        if (!string.Equals(propertyChangedEventArgs.PropertyName, nameof(dto.HasError))) return;
            OnPropertyChanged(() => ErrorMessages);
    }

    public List<string> ErrorMessages => getErrorMessages();

    private List<string> getErrorMessages() {
        //create list in a manner of your choosing
    }

希望这可以帮助人们遇到这种情况。


-1
投票

我们在构造函数之前在get set方法中设置了OnPropertyChanged()方法,这似乎有效!

private bool _theString;
public bool TheString
{
    get { return _theString; }
    set { _theString = value; OnPropertyChanged(); }
}

在.xaml中使用{Binding TheString}

希望这可以帮助!

© www.soinside.com 2019 - 2024. All rights reserved.