【问题标题】:refresh bindings in itemscontrol wpf刷新itemscontrol wpf中的绑定
【发布时间】:2016-06-04 21:27:11
【问题描述】:

我有一个简单的 itemscontrol 绑定到 Entries 对象列表。该按钮更新列表中每个项目的 LastUpdated。如何引发属性更改事件,以便在 ItemsControl 中更新 LastUpdated 字段。我已经简化了我的示例,只是为了找出绑定问题。我的真实示例使用 PRISM 和第三方控件。

C#代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Input;

namespace TestItemsControl
{
    public class Entry
    {
        public string Name { get; set; }

        public DateTime LastUpdated { get; set; }
    }
}

namespace TestItemsControl
{
    public class TestViewModel: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public List<Entry> Entries { get; set; }

        public ICommand UpdateCmd { get; set; }

        public TestViewModel()
        {
            this.Entries = new List<Entry>();
            this.Entries.Add(new Entry{ Name = "1", LastUpdated = DateTime.Now });
            this.Entries.Add(new Entry { Name = "2", LastUpdated = DateTime.Now });
            this.Entries.Add(new Entry { Name = "3", LastUpdated = DateTime.Now });
        }

        public void Refresh()
        {
            if (this.PropertyChanged!= null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Entries"));
            }
        }
    }
}

XAML:

<Application x:Class="TestItemsControl.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:TestItemsControl"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <local:TestViewModel x:Key="viewModel"/>
    </Application.Resources>
</Application>


<Window x:Class="TestItemsControl.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:TestItemsControl"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525" DataContext="{StaticResource viewModel}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <ItemsControl Grid.Row="0" ItemsSource="{Binding Entries}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Vertical"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <TextBlock Text="{Binding Name}"/>
                        <TextBlock Text="{Binding LastUpdated}"/>
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        <Button Grid.Row="1" Content="Update" Click="Button_Click"/>
    </Grid>
</Window>

【问题讨论】:

  • 您是否在某处动态添加新项目?
  • ItemsControl i; i.Items.Refresh();怎么样
  • 没有动态添加项目。只有 LastUpdated 属性的状态会发生变化。发生的情况是,当我为已更改的特定属性引发属性更改事件时,绑定仅发生一次,而不是针对我的示例中 ItemsSource 中的整个项目。有没有一种特殊的方法来为列表中的项目引发属性更改事件?
  • @TrustyCoder 看我的回答
  • 如何将您的 List 更改为 ObservableCollection 用于您的条目。

标签: c# wpf refresh itemscontrol


【解决方案1】:

如果没有人订阅该事件,您必须检查 Null

public class Entry : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public string Name { get; set; }

    DateTime lastUD;
    public DateTime LastUpdated
    {
        get
        {
            return lastUD;
        }
        set
        {
            lastUD = value;
            if(PropertyChanged != NULL)
               PropertyChanged(this, new PropertyChangedEventArgs("LastUpdated"));
        }
    }
}

【讨论】:

    【解决方案2】:

    然后你必须重写你的Entry

    public class Entry: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string Name { get; set; }
    
        DateTime lastUD;
        public DateTime LastUpdated
        {
            get
            {
                return lastUD;
            }
            set
            {
                lastUD = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("LastUpdated"));
            }
        }
    }
    

    另外,将List&lt;Entry&gt; 更改为ObservableCollection&lt;Entry&gt;

    namespace TestItemsControl
    {
        public class TestViewModel
        {
            public ObservableCollection<Entry> Entries=new ObservableCollection<Entry>();
    
            public ICommand UpdateCmd { get; set; }
    
            public TestViewModel()
            {
                this.Entries.Add(new Entry{ Name = "1", LastUpdated = DateTime.Now });
                this.Entries.Add(new Entry { Name = "2", LastUpdated = DateTime.Now });
                this.Entries.Add(new Entry { Name = "3", LastUpdated = DateTime.Now });
            }
        }
    }
    

    这样你就不必调用刷新函数了。

    【讨论】:

      【解决方案3】:

      我认为你必须在这里选择:

      1. 创建一个这样的方法:

        protected void OnPropertyChanged(string) 
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        

      然后,只要你想更新一个属性,你就去:

      OnPropertyChanged("TheNameOfTheProperty");
      

      或者如果你想更新类中的每个属性:

      OnPropertyChanged(string.Empty);
      

      如果您不确定何时更新哪个属性,我建议您使用后者。

      1. 可以,但我建议您不要这样做:实例化一个新列表,添加更新的值,清除原始列表,将原始列表设置为新列表,然后更新列表的属性名称。

      【讨论】:

        【解决方案4】:

        您没有绑定 UpdateCmd 并在任何地方调用 Refresh,除非它在 ​​Click 处理程序中,但您应该使用 MVVM 方法来执行此操作。

        将 Click 事件处理程序更改为 xaml 中视图模型中的命令绑定,如下所示

        <Button Grid.Row="1" Content="Update" Command={Binding UpdateCmd}/>
        

        然后在视图模型的构造函数中绑定创建一个新的 RelayCommand 或任何 ICommand 实现类,在构造函数接受动作委托的地方。

        this.UpdateCmd  = new RelayCommand(this.Update);
        

        您还应该将 Refresh 更改为 Update 以更新条目的时间戳。

        public void Update()
        {
            foreach (var entry in this.Entries)
            {
                entry.LastUpdated = DateTime.Now;
            }
        
            if (this.PropertyChanged!= null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Entries"));
            }
        }
        

        但是你真的应该在你的 Entry 模型上实现 INotifyPropertyChanged 并在属性设置器上引发事件,绑定将被更新而不通知整个集合应该被更新。

        【讨论】:

          猜你喜欢
          • 2011-03-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-05-11
          相关资源
          最近更新 更多