使用 MVVM 定期更新 silverlight 视图

发布于 2024-11-05 14:29:26 字数 752 浏览 0 评论 0原文

我正在尝试在 Silverlight 中使用 MVVM,但我对它还很陌生,所以我对某些事情不太确定。我有一个 silverlight 页面,显示某些服务器端操作的进度。当前进度来自 Web 服务,应该每隔几秒刷新一次(为了便于讨论,假设 10 秒)。

实现这一点的最佳方法是什么?我能想到的选项是:

  1. 在 ViewModel 的 Initalize 方法中初始化 DispatcherTimer 并从 DispatcherTimer 事件刷新视图(将计时器详细信息放入 ViewModel)

  2. 创建 DispatcherTimer 周围的包装器(例如periodicCommandExecutor),它是一个类似于 WindowsForms 中的 Timer 控件的控件或资源,具有一个命令属性,我将其绑定到 ViewModel 中的 Refresh 命令(将计时器详细信息放入视图中)

我认为第二个选项是首选,因为它使 ViewModel 更容易测试,并且 DispatcherTimer 是一个 UI 实现细节,我不希望在我的 ViewModel 中使用它。你同意?

如果是,您将如何创建这样的包装器。我开始制作带有附加属性的 DependencyObject,但我不确定如何将 Interval 等属性值转发到内部 DispatcherTimer。当依赖属性更改并且 DispatcherTimer 不是 DependencyObject 时,Silverlight 似乎不提供任何事件,因此我无法直接对其属性进行数据绑定。

谢谢!

I am trying to use MVVM in Silverlight, but I am quite new to it so I am not quite sure on some things. I have a silverlight page which displays the progress of some server side operation. The current progress comes from a web service and should be refreshed every few seconds (lets say 10 seconds for the sake of the argument).

What is the best way to implement this? The options I could think of was:

  1. Initalize a DispatcherTimer in the Initalize method of my ViewModel and refresh the view from the DispatcherTimer event (putting the timer details in the ViewModel)

  2. Create a wrapper arround DispatcherTimer (e.g. PeriodicCommandExecutor) which would be a Control or resource similar to the Timer control in WindowsForms with a command property that I bind to a Refresh command in the ViewModel (putting the timer details in the View)

I think the second option is preferred, because it makes the ViewModel easier to test and DispatcherTimer is an UI implementation detail which I don't want in my ViewModel propably. Do you agree?

If yes, how would you create such a wrapper. I started doing an DependencyObject with attached properties, but I am not sure how to forward the property values like Interval to the internal DispatcherTimer. Silverlight doesn't seem to provide any events when the dependency properties change and DispatcherTimer is not a DependencyObject so I can't databind directly to its properties.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

五里雾 2024-11-12 14:29:26

为什么要使用 DispatcherTimer?为什么不使用普通的 System.Threading.Timer,它将在后台线程上触发其回调?

如果您将 UI 进度更新放在不显眼的地方(即不在 UI 的中心,可能在底角或状态栏),那么当用户继续他们正在做的事情时,让后台计时器嘎嘎作响。进度值可以填充到视图模型中,并使用绑定显示在 UI 上。这样您就不必占用 UI 线程来调用 Web 服务。

Why use a DispatcherTimer? Why not use an ordinary System.Threading.Timer, which will fire its callback on a background thread?

If you put your UI progress update somewhere inconspicious (i.e. not in the centre of the UI, maybe in a bottom corner or status bar), then have the background timer chugging away while the user carries on with what they were doing. The progress value can be populated into the viewmodel, and shown on the UI using binding. This way you don't have to tie up the UI thread making web service calls.

风轻花落早 2024-11-12 14:29:26

最后,我解决了我的困境,创建了一种行为,该行为定期在您可以指定的 ViewModel 上执行刷新命令。

该行为的代码是这样的
(抱歉VB代码):

Option Strict On

Imports System.Windows.Threading
Imports System.Windows.Interactivity

Namespace View.Behaviors

    Public Class RefreshBehavior
        Inherits Behavior(Of FrameworkElement)



        Public Property Command As ICommand
            Get
                Return DirectCast(GetValue(CommandProperty), ICommand)
            End Get

            Set(ByVal value As ICommand)
                SetValue(CommandProperty, value)
            End Set
        End Property

        Public Shared ReadOnly CommandProperty As DependencyProperty = _
                                   DependencyProperty.Register("Command", _
                                                               GetType(ICommand), GetType(RefreshBehavior), _
                                                               New PropertyMetadata(Nothing))


        Public Property CommandParameter As Object
            Get
                Return GetValue(CommandParameterProperty)
            End Get

            Set(ByVal value As Object)
                SetValue(CommandParameterProperty, value)
            End Set
        End Property

        Public Shared ReadOnly CommandParameterProperty As DependencyProperty = _
                                   DependencyProperty.Register("CommandParameter", _
                                                               GetType(Object), GetType(RefreshBehavior), _
                                                               New PropertyMetadata(Nothing))




        Public Property Interval As TimeSpan
            Get
                Return DirectCast(GetValue(IntervalProperty), TimeSpan)
            End Get

            Set(ByVal value As TimeSpan)
                SetValue(IntervalProperty, value)
            End Set
        End Property

        Public Shared ReadOnly IntervalProperty As DependencyProperty = _
                                   DependencyProperty.Register("Interval", _
                                                               GetType(TimeSpan), GetType(RefreshBehavior), _
                                                               New PropertyMetadata(TimeSpan.Zero, AddressOf OnIntervalUpdate))



        Public Property Enabled As Boolean
            Get
                Return DirectCast(GetValue(EnabledProperty), Boolean)
            End Get

            Set(ByVal value As Boolean)
                SetValue(EnabledProperty, value)
            End Set
        End Property

        Public Shared ReadOnly EnabledProperty As DependencyProperty = _
                               DependencyProperty.Register("Enabled", _
                               GetType(Boolean), GetType(RefreshBehavior), _
                               New PropertyMetadata(False, AddressOf OnEnabledUpdate))




        Dim WithEvents timer As New DispatcherTimer()

        Private Shared Sub OnEnabledUpdate(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
            Dim enable As Boolean = CType(e.NewValue, Boolean)
            Dim executor As RefreshBehavior = CType(d, RefreshBehavior)
            If Not executor.attached Then Return

            Dim timer As DispatcherTimer = executor.timer

            If enable AndAlso Not timer.IsEnabled Then
                timer.Start()
            ElseIf Not enable AndAlso Not timer.IsEnabled Then
                timer.Stop()
            End If
        End Sub

        Private Shared Sub OnIntervalUpdate(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
            Dim executor As RefreshBehavior = CType(d, RefreshBehavior)

            Dim timer As DispatcherTimer = executor.timer
            timer.Interval = CType(e.NewValue, TimeSpan)
        End Sub

        Private WithEvents attachedObject As FrameworkElement

        Private Sub OnUnload(ByVal sender As Object, ByVal e As EventArgs) Handles attachedObject.Unloaded
            timer.Stop()
        End Sub

        Private attached As Boolean = False
        Protected Overrides Sub OnAttached()
            attached = True
            attachedObject = AssociatedObject

            If Enabled Then timer.Start()
            MyBase.OnAttached()
        End Sub

        Protected Overrides Sub OnDetaching()
            timer.Stop()
            attached = False
            attachedObject = Nothing
            MyBase.OnDetaching()
        End Sub

        Private Sub OnTick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer.Tick
            Dim cmd = Command
            Dim parameter = CommandParameter
            If Interval < TimeSpan.MaxValue AndAlso cmd IsNot Nothing AndAlso cmd.CanExecute(parameter) Then
                cmd.Execute(parameter)
            End If
        End Sub
    End Class
End Namespace

你可以这样使用它:

<i:Interaction.Behaviors>
    <Behaviors:RefreshBehavior Enabled="True" Interval="0:0:10" Command="{Binding RefreshPageCommand}" />
</i:Interaction.Behaviors>

我希望它可以帮助有类似问题的人。

At the end I solved my dillema creating a behavior which periodically executes a refresh command on the ViewModel which you can specify.

The code for the behavior is like this
(sorry for VB code):

Option Strict On

Imports System.Windows.Threading
Imports System.Windows.Interactivity

Namespace View.Behaviors

    Public Class RefreshBehavior
        Inherits Behavior(Of FrameworkElement)



        Public Property Command As ICommand
            Get
                Return DirectCast(GetValue(CommandProperty), ICommand)
            End Get

            Set(ByVal value As ICommand)
                SetValue(CommandProperty, value)
            End Set
        End Property

        Public Shared ReadOnly CommandProperty As DependencyProperty = _
                                   DependencyProperty.Register("Command", _
                                                               GetType(ICommand), GetType(RefreshBehavior), _
                                                               New PropertyMetadata(Nothing))


        Public Property CommandParameter As Object
            Get
                Return GetValue(CommandParameterProperty)
            End Get

            Set(ByVal value As Object)
                SetValue(CommandParameterProperty, value)
            End Set
        End Property

        Public Shared ReadOnly CommandParameterProperty As DependencyProperty = _
                                   DependencyProperty.Register("CommandParameter", _
                                                               GetType(Object), GetType(RefreshBehavior), _
                                                               New PropertyMetadata(Nothing))




        Public Property Interval As TimeSpan
            Get
                Return DirectCast(GetValue(IntervalProperty), TimeSpan)
            End Get

            Set(ByVal value As TimeSpan)
                SetValue(IntervalProperty, value)
            End Set
        End Property

        Public Shared ReadOnly IntervalProperty As DependencyProperty = _
                                   DependencyProperty.Register("Interval", _
                                                               GetType(TimeSpan), GetType(RefreshBehavior), _
                                                               New PropertyMetadata(TimeSpan.Zero, AddressOf OnIntervalUpdate))



        Public Property Enabled As Boolean
            Get
                Return DirectCast(GetValue(EnabledProperty), Boolean)
            End Get

            Set(ByVal value As Boolean)
                SetValue(EnabledProperty, value)
            End Set
        End Property

        Public Shared ReadOnly EnabledProperty As DependencyProperty = _
                               DependencyProperty.Register("Enabled", _
                               GetType(Boolean), GetType(RefreshBehavior), _
                               New PropertyMetadata(False, AddressOf OnEnabledUpdate))




        Dim WithEvents timer As New DispatcherTimer()

        Private Shared Sub OnEnabledUpdate(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
            Dim enable As Boolean = CType(e.NewValue, Boolean)
            Dim executor As RefreshBehavior = CType(d, RefreshBehavior)
            If Not executor.attached Then Return

            Dim timer As DispatcherTimer = executor.timer

            If enable AndAlso Not timer.IsEnabled Then
                timer.Start()
            ElseIf Not enable AndAlso Not timer.IsEnabled Then
                timer.Stop()
            End If
        End Sub

        Private Shared Sub OnIntervalUpdate(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
            Dim executor As RefreshBehavior = CType(d, RefreshBehavior)

            Dim timer As DispatcherTimer = executor.timer
            timer.Interval = CType(e.NewValue, TimeSpan)
        End Sub

        Private WithEvents attachedObject As FrameworkElement

        Private Sub OnUnload(ByVal sender As Object, ByVal e As EventArgs) Handles attachedObject.Unloaded
            timer.Stop()
        End Sub

        Private attached As Boolean = False
        Protected Overrides Sub OnAttached()
            attached = True
            attachedObject = AssociatedObject

            If Enabled Then timer.Start()
            MyBase.OnAttached()
        End Sub

        Protected Overrides Sub OnDetaching()
            timer.Stop()
            attached = False
            attachedObject = Nothing
            MyBase.OnDetaching()
        End Sub

        Private Sub OnTick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer.Tick
            Dim cmd = Command
            Dim parameter = CommandParameter
            If Interval < TimeSpan.MaxValue AndAlso cmd IsNot Nothing AndAlso cmd.CanExecute(parameter) Then
                cmd.Execute(parameter)
            End If
        End Sub
    End Class
End Namespace

You can use it like this:

<i:Interaction.Behaviors>
    <Behaviors:RefreshBehavior Enabled="True" Interval="0:0:10" Command="{Binding RefreshPageCommand}" />
</i:Interaction.Behaviors>

I hope it helps someone with a similar problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文