locked
XamlReader.Load and Custom Controls RRS feed

  • Question

  • Hello,

    I've created a custom control, LinkableTextBlock.  The control loads and works properly when placed in a parent canvas at design time as well as when constructed and rendered programmatically from code.  I've had problems understanding how to initialize it from XamlReader.Load, however.

    The call XamlReader.Load("<app:LinkableTextBlock/>"); results in a XamlParseException - undeclared prefix.  I am executing the call in the context of a Page which has already defined the 'app' namespace, however, so I would have thought this would have worked.

    My workaround's been to use XamlReader.Load(@"<Canvas xmlns:app='clr-namespace:ControlTest;assembly=ClientBin/ControlTest.dll'><app:LinkableTextBlock/></Canvas>"), which I can then cast as a Canvas and traverse as necessary to pull out the LinkableTextBlock object.  Would this be the proper approach, or is there a way to make the first method work?

    Thank you in advance,

    -Craig

    Saturday, February 16, 2008 11:35 AM

Answers

  • AFAIK, there is no way to add the content as a typed object using the XamlReader.(in static languages for custom controls)

    add the control to the visual tree without using XamlReader.(adding the control to the visual collection by creating an instance of it)

    but if you want to use the XamlReader, there's a work around with dynamic languages, for example, when you load the content via XamlReader, the control's codebehind is not valid, and events will not fire. but you can use dynamic languages.

    sample code(IronPython) :

    import System
    from System.Windows.Controls import *

    def OnLoaded(sender, args) :
        global root
        root = sender.Parent
        r=TextBlock()
        r.Text="test"
        root.Children.Add(r)

    xaml :

    <Canvas xmlns="http://schemas.microsoft.com/client/2007"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Width="640"
            Height="480"
            Background="White"
            >
      <x:Code Source="UserControl1.Xaml.py" Type="text/python"/>
      <Canvas x:Name="loadHelper" Loaded="OnLoaded"/>
    </Canvas>

    load the xaml via XamlReader, the TextBlock will be added after loading the contents.

     

     

    Sunday, February 17, 2008 7:34 PM

All replies

  • Have you tried just adding the xmlns:app attribute to your LinkableTextBlock element instead? You could also probably just use xmlns="'clr-namespace:ControlTest;assembly=ClientBin/ControlTest.dll" since your Xaml only has the one element from that namespace.

    Saturday, February 16, 2008 12:59 PM
  • Hi Fred,

    The root canvas for the LinkableTextBlock already has the attribute [xmlns:app="clr-namespace:ControlTest;assembly=ClientBin/ControlTest.dll"].  When you say just use "You could also probably just use..." how exactly would you use that..?

    Thanks,

    -Craig

     

    Saturday, February 16, 2008 2:21 PM
  • Hi Craig,

    XamlReader can't verify the app prefix cos that's not a standard xaml prefix, so you can't use the custom prefixes with the XamlReader.

    you should load the whole user control's xaml, something like this:

    System.IO.Stream s = this.GetType().Assembly.GetManifestResourceStream("SilverlightProject3.UserControl1.xaml");

    Children.Add(XamlReader.Load(new System.IO.StreamReader(s).ReadToEnd()) as Visual);

    HTH
    Saturday, February 16, 2008 3:03 PM
  • HTH -

    Loading as you describe above does load the contents of the control, but not as a typed object of the control - it just pulls in the inner contents.   With your suggestion, is there then a way to retrieve the typed object of the custom control in code?

     Thanks,

    -Craig

    Sunday, February 17, 2008 1:09 PM
  • AFAIK, there is no way to add the content as a typed object using the XamlReader.(in static languages for custom controls)

    add the control to the visual tree without using XamlReader.(adding the control to the visual collection by creating an instance of it)

    but if you want to use the XamlReader, there's a work around with dynamic languages, for example, when you load the content via XamlReader, the control's codebehind is not valid, and events will not fire. but you can use dynamic languages.

    sample code(IronPython) :

    import System
    from System.Windows.Controls import *

    def OnLoaded(sender, args) :
        global root
        root = sender.Parent
        r=TextBlock()
        r.Text="test"
        root.Children.Add(r)

    xaml :

    <Canvas xmlns="http://schemas.microsoft.com/client/2007"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Width="640"
            Height="480"
            Background="White"
            >
      <x:Code Source="UserControl1.Xaml.py" Type="text/python"/>
      <Canvas x:Name="loadHelper" Loaded="OnLoaded"/>
    </Canvas>

    load the xaml via XamlReader, the TextBlock will be added after loading the contents.

     

     

    Sunday, February 17, 2008 7:34 PM
  • Thank you for the info.

    The above workaround seems similar enough in concept to what I've implemented - an extension method to string which wraps the xaml in a Canvas with the appropriate xmlns attributes, and then returns the first child, which would be strongly typed to T:

    public static T Load<T>(this string xaml) where T : Visual
    {
        T child = null;

        try
        {
     Canvas c = XamlReader.Load("<Canvas xmlns:app='clr-namespace:ControlTest;assembly=ClientBin/ControlTest.dll' " +     "xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>"
     + xaml + "</Canvas>") as Canvas;

     child = c.Children[0] as T;
     c.Children.Remove(child);
        }
        catch (Exception e)
        {
     Debug.WriteLine(e);
        }

        return child;
    }

     

    -Craig

    Sunday, February 17, 2008 8:28 PM
  • You're welcome.

    nice idea csperler Wink

    Sunday, February 17, 2008 8:56 PM