如何制作每秒更新一次的WPF控件?

发布于 2024-07-24 21:38:19 字数 1195 浏览 6 评论 0原文

这个问题类似于我问的另一个问题,但在这种情况下我想知道如何强制从 XAML 更新绑定或视图模型,在本例中我想了解如何将其包装到自定义 WPF FrameworkElement 中。

我想要的功能是一段文本,指示某件事发生了多久。

<TextBlock Text="It happened " />
<my:AgeTextBlock SinceTime="{Binding OccurredAtUtc}" />
<TextBlock Text=" ago" />

这将呈现为(例如):

发生在 1 分 13 秒前

我有从 TimeSpan 转换为所示的人类可读形式的代码。

为了让 UI 每秒更新一次,我正在考虑使用静态 DispatcherTimer (想法来自 肯特·布加特的回答)。

这就是我的情况:

public class AgeTextBlock : TextBlock
{
    private static readonly DispatcherTimer _timer;

    static AgeTextBlock()
    {
        _timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
    }

    public AgeTextBlock()
    {
        _timer.Tick += ...;
    }

    // How can I unsubscribe from the Tick event to avoid a memory leak?
}

评论表明了我的问题。 我不知道如何用这种方法正确清理。 没有 Dispose 方法可以覆盖和删除事件处理程序。

这里推荐的模式是什么?

This question is similar to another one I asked, but whereas in that case I wanted to know about forcing a binding to update from XAML or a view model, in this case I'd like to know about wrapping this up into a custom WPF FrameworkElement.

The functionality I'm after is a span of text that indicates how long ago something happened.

<TextBlock Text="It happened " />
<my:AgeTextBlock SinceTime="{Binding OccurredAtUtc}" />
<TextBlock Text=" ago" />

This would render as (for example):

It happened 1 min 13 sec ago

I have code that converts from a TimeSpan to the human-readable form shown.

In order to have the UI update every second I'm considering using a static DispatcherTimer (idea from Kent Boogaart's answer).

So here's what I have:

public class AgeTextBlock : TextBlock
{
    private static readonly DispatcherTimer _timer;

    static AgeTextBlock()
    {
        _timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
    }

    public AgeTextBlock()
    {
        _timer.Tick += ...;
    }

    // How can I unsubscribe from the Tick event to avoid a memory leak?
}

The comment indicates my problem. I can't see how I'd clean up properly with this approach. There's no Dispose method to override and remove the event handler.

What is the recommended pattern here?

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

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

发布评论

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

评论(2

乱世争霸 2024-07-31 21:38:20

为什么不在控件的Loaded事件中订阅Tick事件,在Unloaded事件中取消订阅呢?

Why not subscribe to the Tick event in the Loaded event of the control, and unsubscribe in the Unloaded event ?

九命猫 2024-07-31 21:38:20

仅仅因为 TextBlock 没有实现 IDisposable 并不意味着您不能自己添加接口要求和实现。 您可以自己实施处置(不要覆盖基地中的任何内容)并在那里处置您的计时器。

显然,您将负责处理您的 AgeTextBlock 类。 例如,您可以在窗口关闭事件或类似的事件中执行此操作。

(或者,如果您遵循 MVVM 模式,并将计时器放在视图上模型,您可以使视图模型 IDisposable 并将视图绑定到视图模型上的计时器值。)

[编辑:是的,考虑一下,我真的不认为这应该是一个与 Winforms 不同的自定义控件,WPF 不不需要自定义控件,相反,我想我会在视图模型上公开一个计时器属性(可能是一个预先格式化的属性,这样你就有一个很好的可读字符串)并将该属性绑定到普通文本框 - 没有自定义控件 - 然后我将使用样式或模板来调整文本框的视觉属性,以使其看起来像我想要的那样。 听上去怎么样?]

Just because TextBlock doesn't implement IDisposable doesn't mean you can't add the interface requirement and the implementation yourself. You can implement dispose yourself (not overriding anything from the base) and dispose of your timer there.

You will Obviously then be responsible for disposing of your AgeTextBlock class. You'll could do this in your windows closing event for example or something like that.

(Alternately, if you follow the MVVM pattern, and put your timer on the view model, you could make your view model IDisposable and just bind the view to the timer value on the view model.)

[Edit: Yeah, thinking about this, I don't really think this should be a custom control unlike Winforms, WPF doesn't have such a need for custom controls, instead I think I would expose a timer property on my view model (Possibly a pre-formatted property so you have a nice readable string) and bind that property to a normal text box - no custom control - then I would use a style or template to tweak the visual properties of the text box to look how I wanted. How does that sound?]

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