繁体   English   中英

ItemsControl ItemSource 绑定未更新

[英]ItemsControl ItemSource Binding not updating

我曾经只是通过将字符串列表转换为带有换行符的字符串来创建文本块。 此绑定有效; 应该在什么时候更新,但我正在尝试将文本列表移动到 ItemsControl 中,因为它们将需要在将来的某个时候成为超链接。 问题:当 PropertyChangeEvent 被触发时,ItemsControl 不会改变。 相关代码如下:

xml

<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 之外的所有其他控件都有效? 它有什么特别之处?

所以我能够通过使用 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>( );
}
}

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

这不会更新属性的原因是 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
    }

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

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

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

在您的 .xaml 中使用{Binding TheString}

希望这可以帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM