【问题标题】:How to programmatically refresh wpf c#?如何以编程方式刷新 wpf c#?
【发布时间】:2012-06-13 17:43:13
【问题描述】:

这个场景我很好,我让模型解释一下。

public class ScheduleMonthlyPerDayModel 
{
    public DateTime Date { get; set; }

    public string Day 
    { 
        get
        {
            return Date.Day.ToString();
        }
    }

    ObservableCollection<AppointmentDTO> _appointments;
    public ObservableCollection<AppointmentDTO> Appointments 
    {
        get
        {
            return _appointments;
        }
        set
        {
            _appointments = value;

            if (value.Count > 0)
                NotifyOfPropertyChange(() => HasSchedule);
        }
    }

    public bool BelongsToCurrentMonth
    {
        get;
        set;
    }

    public bool HasSchedule
    {
        get
        {
            return _appointments.Count > 0 ? true : false;
        }
    }

    public ScheduleMonthlyPerDayModel()
    {
        _appointments = new ObservableCollection<AppointmentDTO>();
    }

    public void ClearCollection()
    {
        _appointments.Clear();
    }
}

public class ScheduleMonthlyPerWeekModel
{
    public ScheduleMonthlyPerDayModel Sunday{get; set;}

    public ScheduleMonthlyPerDayModel Monday{get; set;}

    public ScheduleMonthlyPerDayModel Tuesday{get; set;}

    public ScheduleMonthlyPerDayModel Wednesday{get; set;}

    public ScheduleMonthlyPerDayModel Thursday{get; set;}

    public ScheduleMonthlyPerDayModel Friday{get; set;}

    public ScheduleMonthlyPerDayModel Saturday{get; set;}
}

与 xaml 的绑定正在使用 xaml 的一瞥,如下所示:

headereditemscontrol itemsSource= weekcollection,其中 weekcollection 是 schedulemonthlyperweekmodel 的对象。

在该 headereditems 控件中,我每天为 schedulemonthlyperweekmodel 的每个属性模板化如下:

<Grid.ColumnDefinitions>
    <ColumnDefinition />
    <ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"  Style="{StaticResource CalendarDates}" Text="{Binding Path=Saturday.Day}" />
<ListBox Grid.Row="1" Grid.ColumnSpan="2" Padding="0" 
         ItemsSource="{Binding Path= Saturday.Appointments}"
         ItemTemplate="{StaticResource myItemStyle}"
         Visibility="{Binding Path=Saturday.HasSchedule, Converter={StaticResource BoolToVisibilityConverter}}" />

基本上,我试图通过每天收集约会来实现每月视图。我的问题是,当我以编程方式将项目添加到例如此处的 saturday.appointments 集合时,通过调试附加项目成功并通知主集合(weekcollection),不会刷新 UI。

我想要实现的是:在我将假定的约会添加到其相应的日期/日期后,用户界面也会相应地更新,但我该怎么做呢?

目前,UI 仅在我更改/切换到不同然后返回时才会更新,之后会很好地显示约会。我想自动化它,因为要求用户在看到约会列表之前切换到其他东西然后返回是很丑​​陋的。

【问题讨论】:

  • NotifyOfPropertyChange 是什么,我没有看到 INotifyPropertyChanged 已实现。
  • 如果你正在绑定控件的数据源,你不应该“刷新”任何东西。
  • 现在,如果您将一个项目添加到 Appointments 集合中,它应该会自动在 ListBox 中显示该项目。但是,当列表从空变为填充时,可见性绑定不会更新。这是真的吗?
  • 是的@Moozhe,这就是为什么我想我需要将当前视图切换到其他视图然后返回以使列表框可见。那么我应该如何进行呢?省略可见性代码在性能方面会更好吗?我尝试关闭视图然后以编程方式返回,但这很丑陋,我希望有更好的行动方案。 @nickbabcock 它是由 schedulemonthlyperdaymodel 继承的,显然我不小心删除了继承。谢谢。
  • 只是一个额外的,我可以离开列表框的可见性,它会工作并显示约会,但我也有 datatriggers 设置为 HasSchedule 属性,当它有约会时会改变单元格背景,所以我认为这涉及相同的问题,如何将内部/辅助属性的更改反映到 xaml 以更新用户界面。

标签: c# wpf binding observablecollection


【解决方案1】:

正如尼克建议的那样,使用 INotifyPropertyChanged 接口是关键。

http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx

如果您希望 ObsCollection 了解属性更改,您必须实现此接口,如上面的链接所示。这将更新在添加、删除或更改某些内容时绑定到的 UI 控件。没有它,您实际上必须跟踪代码中的更改并手动更新它们。

它实际上很容易实现和使用,而且非常棒。如果您不想使用它,您可能只是使用了一个winform。 =)

希望这会有所帮助。

【讨论】:

  • 是的,我真的错了。如上所述,我继承了一个实现 inotify 的类。我可能是困了,在没有注意到的情况下意外删除了它,ScheduleMonthlyPerDayModel 实际上看起来像这个“公共类 ScheduleMonthlyPerDayModel:ViewModelBase”,其中 viewmodelbase 继承自 inotifypropertychanged。真的很抱歉没有注意到丢失的代码。
【解决方案2】:

可见性的问题在于它绑定到一个只读属性,该属性在 get 上计算一个值。因此,它无法通知它已更改。

您的 HasSchedule 属性需要知道 Appointment 属性何时更改。 Appointment 属性的设置器只知道整个列表何时更改。在您的情况下,您需要知道列表的 contents 何时更改。

ObservableCollection 有一个事件告诉您列表的内容何时发生变化,称为 CollectionChanged。您应该执行以下操作以使用此事件通知您的 HasSchedule 属性已更改:

ObservableCollection<AppointmentDTO> _appointments;
public ObservableCollection<AppointmentDTO> Appointments
{
    get
    {
        return _appointments;
    }
    set
    {
        if (_appointments != value)
        {
            if (_appointments != null)
                _appointments.CollectionChanged -= Appointments_CollectionChanged;

            _appointments = value;

            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("HasSchedule"));

            if (_appointments != null)
                _appointments.CollectionChanged += Appointments_CollectionChanged;
        }
    }
}

void Appointments_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs("HasSchedule"));
}

正如您所说,这是假设您在 ViewModel 中实现了 INotifyPropertyChanged。在这种情况下,每次您的集合以某种方式更改时,它都会通知 HasSchedule 属性已更改。如果值发生变化,绑定将刷新值并更新可见性。

【讨论】:

  • 我的错误。 propertychanged 的​​实例化如下: public event PropertyChangedEventHandler PropertyChanged = delegate { };来自视图模型库。
  • 尝试了代码,我没有使用我以前的 Viewmodelbase 继承,而是使用 INotifyPropertyChanged 对其进行了更改,重新编译然后再次测试,添加约会后列表框仍然没有显示。
  • 另一件事,我在将一项添加到约会集合后检查了 hasschedule 值是否发生了变化,它确实发生了变化,所以我猜问题是,新的 bool 值没有反映或刷新 xaml。
  • 您的解释澄清了问题。即使 HasSchedule 属性将值更改为 true,当我填写 schedulemonthlyperdaymodel 的约会时,我也不明白为什么它没有反映到 xaml。所以我尝试了另一种方法,我在模型中创建了一个简单的方法(schedulemonthlyperdaymodel),将项目附加到约会集合,然后通知 hasschedule 属性,解决方案工作并按照我的需要刷新 xaml。谢谢@Moozhe
  • 很高兴能提供帮助。我不确定为什么它不能按原样工作。当您更改整个约会列表时,HasSchedule 可能没有通知更改。我在上面的示例中添加了 2 行代码,它在 Appointments 设置器期间调用 PropertyChanged。也许这会让你的代码更加紧凑和简洁。
猜你喜欢
  • 1970-01-01
  • 2013-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多