WPF Events
在做一个Puzzle,怎么也做不下去了(http://msdn.microsoft.com/en-us/library/ms771766.aspx)
与原来的例子不同的是,我的实现是把Size, ChopElement等做为DependencyProperty,然后在PropertyChange的CallBack函数中更新Layout. 实现的代码摘录如下:
- 登记DependencyProperty
代码
public int PuzzleColumnCount
{
get { return (int)this.GetValue(PuzzleColumnCountProperty); }
set { this.SetValue(PuzzleColumnCountProperty, value); }
}
public static readonly DependencyProperty PuzzleColumnCountProperty = DependencyProperty.Register(
"PuzzleColumnCount", typeof(int), typeof(PuzzleControl),
new FrameworkPropertyMetadata(new PropertyChangedCallback(OnPuzzleGridChangedCallback)));
- 登记处理事件,并且重新UpdateLayout
{
ConstructLayout();
}
逻辑非常简单。但是却发现,由于在函数ConstructLayout中,会动态的生成一些VisualElment,这些VisualElment需要Applytempate,并且设置值。
不幸的是,在这个时候,并不能保证这些VisualElment的Template里的子VisualTree已经生成。
那么,把这段代码放到Loaded里面,是否可行呢? 还是不行。NND
Action | Control instantiated in XAML | Control instantiated in code |
Control ctor | As soon as begin tag is parsed. | When you call it. |
Explicit Style applied | If the Style property is set in XAML, it will be applied as soon as the end tag is parsed. | As soon as Style property is set. |
Built-in Style (from generic.xaml) applied | As soon as the end tag is parsed, after the explicit Style (if any) has been applied. Will not override explicit Style. | When the control enters the tree. Will not override explicit Style. |
Properties set | When the attributes are parsed. | When you set them. |
Loaded event | Posted when the element is been added to the tree. Fired before the next frame. Happens before layout. | Same. |
Template applied (i.e. control's visual are created from the Template) | In the Measure pass of layout. The Template property will be applied if the control has no visual tree. The control starts life with no visual tree, and the visual tree will be cleared when the Template property is set. You can also call ApplyTemplate yourself. | Same. |
OnApplyTemplate called | Whenever the Template is applied. It is not necessary to call the base OnApplyTemplate for the Template to be applied, but inherited types might be relying on it for their implementations. | Same. |
Visuals first available | In OnApplyTemplate. Use GetTemplateChild. | Same. |
MeasureOverride called | In the Measure pass of layout. If the Template was expanded during this Measure pass, MeasureOverride will be called after the Template has been expanded. | Same. |
ArrangeOverride called | In the Arrange pass of layout, which occurs after the Measure pass. | Same. |
SizeChanged event | After the Measure and Arrange passes have completed. | Same. |
LayoutUpdated event | After SizeChanged events have fired. | Same. |
Extracted from:http://blogs.msdn.com/devdave/archive/2008/10/11/control-lifecycle.aspx
以及 http://blogs.msdn.com/silverlight_sdk/archive/2008/10/24/loaded-event-timing-in-silverlight.aspx
this case, calls to the Silverlight VisualTreeHelper API to “walk” the visual tree of the template content might not work if you make them directly from a Loaded handler.
In the RTM release of the documentation on MSDN (and the offline version for Visual Studio's collections), we documented Silverlight's Loaded by re-using the same description as WPF had: "Occurs when a FrameworkElement has completed layout passes, has rendered, and is ready for interaction." In terms of Silverlight's timeline of events and callbacks for a control or other object, that description is not correct. A better description would be : "Occurs when a FrameworkElement has been constructed and added to the object tree." Because of how Silverlight processes templates, the visual tree construction aspect of the visual tree under that object might still be pending as of the Silverlight Loaded event. (We'll be changing the Loaded description as well as adding remarks to an upcoming Silverlight reference refresh on MSDN.)
If you are trying to use the Silverlight Loaded in the same sense as you might have used the WPF Loaded, there are several possible workarounds. Each has merits as well as possible limitations.
1) If you are subclassing from an existing control, rather than adding handling for Loaded, you can override OnApplyTemplate. OnApplyTemplate is specifically intended as the callback for this situation, where you have a tree from the template and now you want to walk it either to examine or to adjust the visuals. The limitation here is that if you are just consuming an existing control as part of your application, you can’t change anything about OnApplyTemplate, it is defined by the control.
2) You can still continue to use Loaded. However, as the very first call in your Loaded handler, call Control.ApplyTemplate on that control. ApplyTemplate is a synchronous method, so once you make that call and it comes back, your template-created visual tree is now present. While it might appear that calling ApplyTemplate is forcing the issue of something that was already happening, an explicit ApplyTemplate call does not duplicate effort on the part of the various Silverlight subsystems (render, layout, etc.). To use this approach, your element of concern does need to be a Control as opposed to a FrameworkElement, and there has to be an actual template involved (so typically this is appropriate for a ContentControl or ItemsControl).
3) You can handle LayoutUpdated instead of Loaded. LayoutUpdated is the last “object lifetime” event in the sequence of spinning up a control in Silverlight UI. The main limitation with LayoutUpdated is that the initialization seequence is not the only time that LayoutUpdated might be raised. Also, LayoutUpdated is raised for objects that are involved in a layout change (for instance, a peer in layout might have changed its size. In terms of visual trees, even the peer object may have changed only changed a few property values and not the tree structure, and the visual tree of the object that you care about might not have changed at all. Therefore you might have to apply your own throttling or logic to determine whether a LayoutUpdated event really means that you need to examine or re-examine a visual tree.
Note that there are a lot of scenarios for handling Loaded that are not impacted by the timing issues of when a template is applied. For instance, you can still add event handlers or set properties for the object where Loaded is handled, you just can’t get into the template parts quite yet. For instance, you can create objects in code and add them into content properties or content collections at this time, or add input-type event handlers that you chose not to hook up in the initial XAML.
Another improvement we are trying to get into the SDK documentation is a more complete timeline of all the callbacks and events that you might be interested in, either as a control consumer or as a control author, including where Loaded falls in the sequence. Another Microsoft Silverlight blogger, Dave Relyea, has put up this post on the control object timeline, check it out.