惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google Online Security Blog
Google Online Security Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
C
CERT Recently Published Vulnerability Notes
C
Cybersecurity and Infrastructure Security Agency CISA
Cisco Talos Blog
Cisco Talos Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
Scott Helme
Scott Helme
Project Zero
Project Zero
E
Exploit-DB.com RSS Feed
S
Secure Thoughts
K
Kaspersky official blog
L
Lohrmann on Cybersecurity
NISL@THU
NISL@THU
WordPress大学
WordPress大学
N
News and Events Feed by Topic
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LINUX DO - 热门话题
小众软件
小众软件
P
Privacy & Cybersecurity Law Blog
博客园 - 聂微东
Google DeepMind News
Google DeepMind News
H
Hackread – Cybersecurity News, Data Breaches, AI and More
A
About on SuperTechFans
Hacker News: Ask HN
Hacker News: Ask HN
AWS News Blog
AWS News Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
H
Hacker News: Front Page
F
Full Disclosure
Latest news
Latest news
Schneier on Security
Schneier on Security
The Hacker News
The Hacker News
T
Troy Hunt's Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Jina AI
Jina AI
Martin Fowler
Martin Fowler
P
Proofpoint News Feed
TaoSecurity Blog
TaoSecurity Blog
G
GRAHAM CLULEY
Forbes - Security
Forbes - Security
V
V2EX - 技术
酷 壳 – CoolShell
酷 壳 – CoolShell
V
Vulnerabilities – Threatpost
C
Cyber Attacks, Cyber Crime and Cyber Security
MongoDB | Blog
MongoDB | Blog
博客园 - 三生石上(FineUI控件)
S
SegmentFault 最新的问题
Hugging Face - Blog
Hugging Face - Blog
P
Privacy International News Feed
C
Check Point Blog
N
News and Events Feed by Topic

博客园 - winkingzhang

Build 2016概览 WinRT开发系列之编程语言:功能和效率 WinRT开发系列之基础概念:WinRT不是…… VS2010 Extension实践(3)——实现自定义配置 [VS2010 Extension]PowerExtension.GoToDefinition VS2010 Extension实践(2) VS2010 Extension实践 如何通过反射调用带有ref或者out的参数的方法[迁移] Win7硬盘安装和移动硬盘访问出错的修复办法[迁移] zt. Windows Mobile开发文章收藏 [WPF]在Style中设置ToolTip的问题分析 [WPF]RadioButton在Group的Header区部分不响应鼠标选择的bug分析 How to Get IIS Web Sites Information Programmatically Visual Studio 调试器 Application Request Routing and the IIS 7.0 Web Management Service Reference Resources for MOSS and WSS FileSystemWatcher事件多次触发的解决方法 ASP.NET Application Life Cycle CAS and Native Code
WPF模式思考 (zt)
winkingzhang · 2008-12-01 · via 博客园 - winkingzhang

Introduction

Since XAML things have become a bit complicated in trying to conceptualize MVC architectures for Windows applications. The gap between web and win is narrowing and the whole WPF thing adds diverse possibilities to one’s toobox. What to use? Model-view-controler, the model-view-presenter or the new paradigm called model-view-viewmodel?

I have tried to understand what it’s all about and this is what I found out.

What’s the problem?

WPF has changed a few things:

  • through declarative programming (i.e. XAML) a lot of plumbing is created for you which especially in the context of databinding saves a lot of code. Another area is e.g. animations and styling; what previously had to be programmed in C# is now possible inside XAML through triggers or events.
  • in the MVC pattern the View is presenting the data from the Model but now XAML does this job and sometimes need things like value converters or the ObservableCollection to update the presentation
  • user controls in WPF allow you to define a default generic.xaml style which can be overriden when used inside an application, i.e. styling of existing controls is a new feature which adds flexibility to the presentation of the Model
  • XAML allows a wide variety of mechanisms to change things or to react to user actions; through the ICommand that is now defined in the framework, through triggers in XAML, through animations, through event bubbling or tunneling (which is also new)

The MVVM architecture

Overview

MVVM

DataModel

DataModel is responsible for exposing data in a way that is easily consumable by WPF. All of its public APIs must be called on the UI thread only. It must implement INotifyPropertyChanged and/or INotifyCollectionChanged as appropriate. When data is expensive to fetch, it abstracts away the expensive operations, never blocking the UI thread (that is evil!). It also keeps the data “live” and can be used to combine data from multiple sources. These sorts of classes are fairly straightforward to unit test.

ViewModel

A ViewModel is a model for a view in the application (duh!). It exposes data relevant to the view and exposes the behaviors for the views, usually with Commands. The model is fairly specific to a view in the application, but does not subclass from any WPF classes or make assumptions about the UI that will be bound to it. Since they are separate from the actual UI, these classes are also relatively straightforward to unit test.

View

A View is the actual UI behind a view in the application. The pattern we use is to set the DataContext of a view to its ViewModel. This makes it easy to get to the ViewModel through binding. It also matches the DataTemplate/Data pattern of WPF. Ideally, the view can be implemented purely as Xaml with no code behind. The attached property trick comes in very handy for this.

The lines between DataModels and ViewModels can be blurry. DataModels are often shown in the UI with some DataTemplate, which isn’t really so different than the way we use ViewModels. However, the distinction usually makes sense in practice. I also want to point out that there’s often composition at many layers. ViewModels may compose other ViewModels and DataModels. And, DataModels may be composed of other DataModels.

The ViewModel is a model of the view. That means: You want to DataBind a property from
your DataObject (model) to a property from your ViewObject (view) but you sometimes cannot bind directly to a CLR property of the model (because of converting or calculating). This is when ViewModel comes into play. It propagates the already calculated or converted value from your model, so you can bind this property directly to the view property.

The main thrust of the Model/View/ViewModel architecture seems to be that on top of the data (”the Model”), there’s another layer of non-visual components (”the ViewModel”) that map the concepts of the data more closely to the concepts of the view of the data (”the View”). It’s the ViewModel that the View binds to, not the Model directly.

The model

Using the INotifyPropertyChanged you can bubble changes up the stack. The reason that public methods should be on the UI thread is because the model could call long running or async stuff which would block the UI, though there are methods to let the UI thread handle property changes from a separate thread. See the doc on the Dispatcher object and the WPF threading model for more on this. Note in this context that you can let things happen in the background by means of the BeginInvoke() method of the Dispatcher and the paramter that specifies the priority. The SystemIdle in particular is interesting to be used when the Dispatcher is not busy.

The DataModel you can find in the download is mimiced from the Dan Crevier’s sample and can serve as an abstract base class for your own models.

Dispatcher things

The DispatcherTimer is reevaluated at the top of every Dispatcher loop.

Timers are not guaranteed to execute exactly when the time interval occurs, but are guaranteed to not execute before the time interval occurs. This is because DispatcherTimer operations are placed on the Dispatcher queue like other operations. When the DispatcherTimer operation executes is dependent on the other jobs in the queue and their priorities.

If a System.Timers.Timer is used in a WPF application, it is worth noting that the System.Timers.Timer runs on a different thread then the user interface (UI) thread. In order to access objects on the user interface (UI) thread, it is necessary to post the operation onto the Dispatcher of the user interface (UI) thread using Invoke or BeginInvoke. For an example of using a System.Timers.Timer, see the Disable Command Source Via System Timer sample. Reasons for using a DispatcherTimer opposed to a System.Timers.Timer are that the DispatcherTimer runs on the same thread as the Dispatcher and a DispatcherPriority can be set on the DispatcherTimer.

A DispatcherTimer will keep an object alive whenever the object’s methods are bound to the timer.

So, the right way to schedule things inside the WPF UI is something like;
[csharp]
private DispatcherTimer _timer;
timer = new DispatcherTimer(DispatcherPriority.Background);
timer.Interval = TimeSpan.FromMinutes(5);
timer.Tick += delegate { ScheduleUpdate(); };
timer.Start();

[/csharp]
the timer is injected implicitly in the thread associated to the dispatcher of the UI.

References