Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/silverlight/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Silverlight 如何通知视图应获取计算字段的新值_Silverlight_Windows Phone 7_Mvvm - Fatal编程技术网

Silverlight 如何通知视图应获取计算字段的新值

Silverlight 如何通知视图应获取计算字段的新值,silverlight,windows-phone-7,mvvm,Silverlight,Windows Phone 7,Mvvm,我正在开发一个WP7应用程序,它会在一个页面上显示一些时间。我有一个代码,它有一个可观察的对象集合。每个对象都有一个使用DateTime的计算属性。现在来确定页面上显示的时间。我不知道如何“通知”属性已更改,因为属性没有更改,当前时间正在更改(仅每秒一次)。有什么想法吗?以下是我得到的最新信息: //my business object public class Widget { private string _name; public string Name {

我正在开发一个WP7应用程序,它会在一个页面上显示一些时间。我有一个代码,它有一个可观察的对象集合。每个对象都有一个使用DateTime的计算属性。现在来确定页面上显示的时间。我不知道如何“通知”属性已更改,因为属性没有更改,当前时间正在更改(仅每秒一次)。有什么想法吗?以下是我得到的最新信息:

//my business object
public class Widget
{
    private string _name;
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

    private DateTime? _start;
    public DateTime? Start
    {
        get { return _start; }
        set { _start = value; }
    }

    public TimeSpan? TimeSinceStart
    {
        get { return Start.HasValue ? DateTime.Now - Start.Value : default(TimeSpan); }
    }
}

//my viewmodel
public class WidgetDisplayerViewModel : BaseViewModel
{
    public WidgetDisplayerViewModel()
    {
        TimeUpdateTimer.Tick += new EventHandler(TimeUpdateTimer_Tick);
        TimeUpdateTimer.Interval = new TimeSpan(0, 0, 1);
        TimeUpdateTimer.Start();
    }

    public WidgetDisplayerViewModel(string selectedCategory) : this()
    {
        Category = MockDataService.GetCategory(selectedCategory);
        Category.Widgets = MockDataService.GetWidgets(selectedCategory).ToObservableCollection();
    }

    public DispatcherTimer TimeUpdateTimer = new DispatcherTimer();

    private DateTime _currentTime;
    public DateTime CurrentTime
    {
        get { return _currentTime; }
        set {
            _currentTime = value;
            NotifyPropertyChanged("CurrentTime");
        }
    }


    public Category Category { get; set; }

    void TimeUpdateTimer_Tick(object sender, EventArgs e)
    {
        CurrentTime = DateTime.Now;
    }
}
然后视图非常简单,只需要显示CurrentTime,然后对于集合中的每个小部件,它需要显示TimesRunStart。计时器每秒更新CurrentTime,并将其传播到视图中。这很简单,因为计时器正在设置它,所以我有机会调用NotifyPropertyChanged(“CurrentTime”),但是我如何“通知”所有TimesEnter应该被调用以更新每个小部件的计算值,因为我没有设置它们


谢谢

为指定属性调用NotifyPropertyChanged方法

public DateTime CurrentTime
{
    get { return _currentTime; }
    set {
        _currentTime = value;
        NotifyPropertyChanged("CurrentTime");
        NotifyPropertyChanged("TimeSinceStart");
    }
}

您必须以某种方式手动刷新属性。我看你已经有一个计时器每秒钟都在滴答作响了。因此,我可以向您推荐两种解决方案:

1/在小部件对象中定义“UpdateTime”方法。在此方法中,调用NotifyPropertyChanged(“TimesRunStart”)。当计时器滴答作响时,枚举小部件列表,并对每个小部件调用UpdateTime方法


2/创建一个全局对象,实现INotifyPropertyChanged接口,并保存CurrentTime的值。使每个小部件对象订阅此全局类的PropertyChanged事件,以了解时间何时更新。然后,当事件被触发时,调用NotifyPropertyChanged(“TimesRunStart”)

这可能是一个棘手的问题,很快就会变得非常混乱

我建议您坚持目前的做法,只使用一个在主视图模型中初始化的计时器。然后,您必须问自己一个问题-小部件的年龄(TimesRunStart)是否属于小部件,还是纯粹用于显示/信息目的?它是每个小部件在其生命周期内必须保存的核心信息吗

在我看来,这只是为了展示。所以我的建议是:一旦调用了
GetWidgets
,就可以枚举每个小部件,并将其包装在自己的瘦视图模型中。该viewmodel的构造函数接受两个参数——主viewmodel中的计时器和小部件。然后订阅计时器的
Tick
事件,并从中通知
timessrenstart
属性已更改

public class WidgetWrapper : INotifyPropertyChanged
{
    public WidgetWrapper(DispatcherTimer timer, Widget widget)
    {
        _widget = widget;
        timer.Tick += TimerTick;
    }

    private void TimerTick(object sender, EventArgs e)
    {
        OnPropertyChanged("TimeSinceStart");
    }

    public Widget Widget { get { return _widget; } }

    public TimeSpan? TimeSinceStart
    {
        get { return _widget.Start.HasValue ? DateTime.Now - _widget.Start.Value : default(TimeSpan); }
    } 

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

    public event PropertyChangedEventHandler PropertyChanged;

    private readonly Widget _widget;
}


public class WidgetDisplayerViewModel : BaseViewModel
{

    public WidgetDisplayerViewModel(string selectedCategory) : this()
    {
        Category = MockDataService.GetCategory(selectedCategory);
        var wrappedWidgets = new ObservableCollection<WidgetWrapper>();
        MockDataService.GetWidgets(selectedCategory).ForEach(widget => wrappedWidgets.Add(new WidgetWrapper(TimeUpdateTimer, widget)));
        Category.Widgets = wrappedWidgets;
    }
}
公共类WidgetWrapper:INotifyPropertyChanged
{
公共WidgetWrapper(分派器计时器、小部件)
{
_小部件=小部件;
timer.Tick+=TimerTick;
}
私有void TimerTick(对象发送方、事件参数)
{
OnPropertyChanged(“TimesRunStart”);
}
公共小部件{get{return\u Widget;}}
公共TimeSpan?TimesRunStart
{
获取{return _widget.Start.HasValue?DateTime.Now-_widget.Start.Value:default(TimeSpan);}
} 
私有void OnPropertyChanged(字符串propertyName)
{
if(PropertyChanged!=null)
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
公共事件属性更改事件处理程序属性更改;
私有只读小部件_小部件;
}
公共类WidgetDisplayerViewModel:BaseViewModel
{
公共WidgetDisplayerViewModel(字符串selectedCategory):this()
{
Category=MockDataService.GetCategory(selectedCategory);
var wrappedWidgets=newobserveCollection();
MockDataService.GetWidgets(selectedCategory.ForEach(widget=>wrappedWidgets.Add(newwidgetwrapper(TimeUpdateTimer,widget)));
Category.Widgets=wrappedWidgets;
}
}

在向实体添加功能时,使用自己的viewmodel包装DTO(实体、数据传输对象)是一种非常常见的方法。如果使用此方法,则必须稍微修改以小部件上的属性为目标的任何UI绑定,因为这些UI元素现在将处理WidgetWrapper(或者您只需在WidgetWrapper本身中显示所需的属性,则无需更改任何绑定)

 private Widget()
 {
      App.ViewModel.PropertyChanged += (s, e) =>
      {
           if (e.PropertyName.Equals("CurrentTime")
           {
                NotifyPropertyChanged("TimeSinceStart");
           }
      };
 }

这根本不起作用,因为
TimesRunStart
在小部件对象上,而
CurrentTime
在viewmodel上。那么您将如何实现属性通知?它要么在小部件上更改了NotifyProperty,或者公开widget并通知widget属性。这不会使模型依赖于viewmodel吗?这不是很理想吗?我会采用这种方法,除非我尝试不包装widget对象,除非必要,并且下面的建议很好,并且不需要包装。谢谢你的回答!我最终选择了第一名。我在我的viewmodel中添加了一个方法(“Refresh()”),并枚举小部件对象并调用它们的NotifyPropertyChanged。它确实要求我将NotifyPropertyChanged方法从protected更改为public。我不认为他们在架构上有什么问题,但一开始似乎有点奇怪。非常感谢你的回答!事实上,把它擦掉。我发现以下内容可以添加为我的BaseModel(该小部件源自)的公共方法,它允许我一次更新所有属性。我甚至不知道它是怎么工作的,但它太棒了。public void Refresh(){PropertyChanged(null,new PropertyChangedEventArgs(“”);}“我甚至不知道它是如何工作的/为什么工作的”->在规范中:p使用空字符串调用PropertyChanged意味着