<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Loaded="onLoaded" />
The Object Tree and FindName
Even if there are no named objects, you can still get into the object tree at run time through the Root property on the Silverlight plug-in. This returns the object that is the root of the loaded XAML.
The Object Tree and CreateFromXaml
To add XAML content dynamically to the tree structure after the initial loading of the source XAML, you first create the XAML fragment by using the CreateFromXaml method. At this point, the XAML fragment you create is disconnected from the Silverlight object tree. This means that the fragment is not rendered yet. However, even before adding it to the object tree, you can modify the properties of the objects in the XAML fragment. Object methods cannot be invoked prior to connecting the tree.
After you have created a disconnected object set from your XAML fragment, you generally will want to add it to the active Silverlight object tree. The fragment can either be added as a child object to a parent object, or it can set a property value of an object. When the fragment becomes part of the Silverlight object tree, the objects in the XAML fragment are rendered. Depending on the extent of the XAML provided as CreateFromXaml input, you can create a single Silverlight object, such as a TextBlock, or a complex tree of Silverlight objects.
There are several requirements for adding XAML content dynamically to the Silverlight object tree:
There must be existing XAML content associated with the Silverlight plug-in. You cannot use CreateFromXaml to replace the entire tree of content; you must at least preserve the original root element. If you want to replace the entire tree, you can set Source, although note that Source requires an actual file to exist at a URI, and cannot be initialized with just a string. However, you can work around this issue by using inline XAML as the Source, and using the HTML DOM to document.write the contents of the SCRIPT block that contains the intended source XAML.
XAML content that is created by using the CreateFromXaml method can be assigned to only one object. If you want to add objects created from identical XAML to different areas of the application, you must invoke CreateFromXaml multiple times and use different variables for the return value. (If you do this, be careful of name collisions; see Creating Namescopes with CreateFromXAML later in this topic.)
The Silverlight object that will contain the new XAML content must be capable of encapsulating an object, either as a child element or as a property value.
The string you specify for xamlContent of CreateFromXaml must specify well-formed XML (in particular, it must have a single root element). CreateFromXaml will fail and cause an error if the provided XML string is not well formed.
The root element is implicitly using the Silverlight XML namespace. You can set the Silverlight namespace explicitly, but do not set the default XML namespace to any other value other than the Silverlight namespace.
Creating XAML Namescopes with CreateFromXAML
XAML used for CreateFromXaml can have values defined for Name or x:Name. As part of the CreateFromXaml call, a preliminary XAML namescope is created, based on the root of the provided XAML. This preliminary namescope evaluates any defined names in the provided XAML for uniqueness. If names in the provided XAML are not internally unique at this point, CreateFromXaml throws an error. However, if names in the provided XAML collide with names that are already in the primary XAML namescope, no errors occur immediately. This is because when the CreateFromXaml method is called, the created object tree that is returned is disconnected. You must explicitly connect your created object tree, either by adding it to a content property collection such as Canvas.Children or by setting some other property that takes an object value (such as specifying a new ImageBrush for a Fill property value). You will see name collisions causing errors only after you attempt to connect the disconnected object tree to the application's main object tree. The method or property used for the attempted connection will be the source of the error, and the attempted connection will fail (your disconnected tree will remain disconnected).
CreateFromXaml has an optional parameter, createNameScope, which normally defaults to false. Explicitly setting this value to true in the CreateFromXaml call that you use to create a disconnected object tree still creates a preliminary XAML namescope that evaluates any defined names in the provided XAML for uniqueness. If names in the provided XAML are not internally unique at this point, CreateFromXaml throws an error. The difference in the behavior is that the disconnected object tree is now flagged to not attempt to merge its XAML namescope with the primary XAML namescope when it is connected to the main application object tree. After you connect the trees, in effect, your application will have a unified object tree but discrete XAML namescopes. A name defined at the CreateFromXaml root or on any object in the previously disconnected tree is not associated with the primary XAML namescope; it has its own discrete XAML namescope.
The complication with having discrete XAML namescopes is that calls to the FindName method no longer operate against a unified namescope. Instead, the particular object that FindName is called on will imply the scope, with the scope being the XAML namescope that the calling object is within. Therefore, if you attempt to call FindName to get a named object in the primary XAML namescope, it will not find the objects from a discrete XAML namescope created by CreateFromXaml. Conversely, calling FindName from the discrete XAML namescope will not find named objects in the primary XAML namescope. The FindName method defined on the Silverlightplug-in object does not entirely work around this issue; its XAML namescope is always the primary XAML namescope.
This discrete XAML namescope issue only affects XAML namescopes and the FindName call. You can still walk the object tree structure upward in some cases by calling the GetParent method, or downward by calling into the relevant collection properties or properties (such as the collection returned by Canvas.Children).
To get to objects that are defined in a discrete XAML namescope, you can use several techniques:
Walk the object tree with GetParent and/or collection properties.
If you are calling from a discrete XAML namescope and want the primary XAML namescope, it is always easy to get a reference to the Silverlight plug-in and then call FindName on it. The concatenated script call for doing this in a single line is as follows:
returnedObject = object.GetHost().content.FindName("nameToFind");
where object is the calling object in a discrete XAML namescope. The .content in this syntax is the step through to the specific Silverlight plug-in sub-object that defines the FindName method.
If you are calling from the primary XAML namescope and want an object within a discrete XAML namescope, you should plan ahead in your code and retain a reference to the object that was returned by CreateFromXaml. This object is now a valid object for calling FindName within the discrete XAML namescope. You could keep this object as a global variable or otherwise pass it by using method parameters.