.NET 4.0 beta 2已经引入了IObservable和IObserver接口。
与传统的.NET事件相比,有什么优势?这难道没有解决同样的问题吗?
.NET 4.0 beta 2已经引入了IObservable和IObserver接口。
与传统的.NET事件相比,有什么优势?这难道没有解决同样的问题吗?
// A content control is a control that displays content. That content can be
// anything at all like a string or another control. Every content control contains
// another control: a ContentPresenter. The ContentPresenter's job is to generate
// a visual representation of the Content property. For example, if the Content property
// of the ContentControl is a string, the ContentPresenter creates a TextBlock and inserts
// the string into it. On the other hand if the Content property is another control the
// ContentPresenter just inserts it into the visual tree directly.
public class MyContentControl : ContentControl
{
// A subject implements both IObservable and IObserver. When IObserver methods
// are called, it forwards those calls to all of its listeners.
// As a result it has roughly the same semantics as an event that we can "raise."
private Subject<object> contentChanged = new Subject<object>();
// This is a reference to the ContentPresenter in the ContentControl's template
private ContentPresenter contentPresenter;
// This is a reference to the Image control within ContentControl's template. It is displayed on top of the ContentPresenter and has a cool blur effect applied to it.
private Image contentImageControl;
public MyContentControl()
{
// Using Rx we can create specific events from general events.
// In this case I want to create a specific event ("contentImageChanged") which
// gives me exactly the data I need to respond and update the UI.
var contentImageChanged =
// get the content from the content changed event
from content in contentChanged
where content != null
// Wait for the ContentPresenter's visual representation to update.
// ContentPresenter is data bound to the Content property, so it will
// update momentarily.
from _ in contentPresenter.GetLayoutUpdated().Take(1)
select new WritableBitmap(contentPresenter, new TranslateTransform());
contentImageChanged.Subscribe(
contentImage =>
{
// Hide the content presenter now that we've taken a screen shot
contentPresenter.Visibility = Visibility.Collapsed;
// Set the image source of the image control to the snapshot
contentImageControl.ImageSource = contentImage;
});
}
// This method is invoked when the Content property is changed.
protected override OnContentChanged(object oldContent, object newContent)
{
// show the content presenter before taking screenshot
contentPresenter.Visibility = Visibility.Visible;
// raise the content changed "event"
contentChanged.OnNext(newContent);
base.OnContentChanged(oldContent, newContent);
}
}
这个例子特别简单,因为只有两个连续的操作序列。即使在这个简单的示例中,我们也可以看到 Rx 的价值。如果没有它,我将不得不使用状态变量来确保事件按照特定顺序触发。我还必须编写一些非常丑陋的代码来显式地从 LayoutUpdated 事件分离。
当你使用 Rx 进行编程时,关键是要思考“我希望我的框架提供什么事件?”然后去创建它。我们通常认为事件是简单的、由输入驱动的事物(例如“mouseover”、“mouseclick”、“keyup”等)。但是,事件也可以是非常复杂和特定于您的应用程序的(例如“GoogleMsdnMashupStockDataArrived”、“DragStarting”和“ImageContentChanged”)。当您以这种方式组织程序时(精确地创建我需要的事件,然后通过更改状态响应它),您会发现它们具有更少的状态错误,更有序,并且总体上更容易理解。
明白了吗? :-)
Error
属性需要检查的EventArgs
类。
通知结束通知
传统事件需要单独的事件或者一个带有Final
属性需要检查的EventArgs
类。