首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ItemsControl ItemSource绑定不更新

ItemsControl ItemSource绑定不更新
EN

Stack Overflow用户
提问于 2016-11-23 16:43:31
回答 3查看 3.9K关注 0票数 0

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

Xaml

代码语言:javascript
复制
<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>

ViewModel

代码语言:javascript
复制
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; }

        ...
}

就因为我知道人们可能会要求看..。

代码语言:javascript
复制
   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都有效?它有什么特别之处?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-11-23 17:07:15

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

代码语言:javascript
复制
<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>

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2018-03-02 18:38:19

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

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

代码语言:javascript
复制
    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
    }

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

票数 3
EN

Stack Overflow用户

发布于 2016-11-23 16:45:11

我们在构造函数之前的get集合方法中设置了OnPropertyChanged()方法,这似乎是可行的!

代码语言:javascript
复制
private bool _theString;
public bool TheString
{
    get { return _theString; }
    set { _theString = value; OnPropertyChanged(); }
}

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

希望这能有所帮助!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40769941

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档