none
Porting a 1.1 project to 2.0 - Usercontrol inheritance and nested resources

    Question

  • Hey all.

    I am in the process of converting a pretty big 1.1 project to 2.0 and I have a couple of questions;

    1. The original code uses controls as resources (build action: embedded resources) and they are loading the xaml from the Manifest Resource Stream to initiate the controls. That does still work, however it doesn't work on nested controls. ie:

    If Control2 is inside Control1 it's fails when trying to XamlReader.Load (XamlParseException) Control1 to add it on a page . I recreated this with a very simple example and as far as I can see this just doesn't work anymore.

    2. When using usercontrol I would like to use a base class like you can do in WPF (see this post for example: http://geekswithblogs.net/lbugnion/archive/2007/03/02/107747.aspx) but this as well gives me XamlParseException. It's kind of strange because the editor seems to support it fine. It does work if you don't do the xaml bit but then you have to manually change the *g.cs file anytime you do a change.

    I can of course fix these things with workaround but it's a project with 100+ controls and I would to not have to rebuild them all. So if anyone know to fix either one of the two please let me know.

    Cheers,

    -Thomas-

    Saturday, March 08, 2008 12:25 AM

Answers

  • 'm surprised to see this works:
     

    :)  The solution that I found is breaking the SL rules? :) How can we add our own namespace to  http://schemas.microsoft.com/client/2007?

    Tuesday, March 11, 2008 1:39 AM
  • You're right. This can be a work round.

    In the class library project's AssemblyInfo.cs file, add this:

    [assembly: XmlnsDefinition("http://schemas.microsoft.com/client/2007", "YourNamespace")]

    Now after you add reference to this assembly in your main project, you can use any classes in this namespace in your XAML files.

    But without the namespace mapping, your original code should not work. So this still seems to be an issue...

    Tuesday, March 11, 2008 2:03 AM

All replies

  • Hello Thomas,

    If Control2 is inside Control1 it's fails when trying to XamlReader.Load (XamlParseException) Control1 to add it on a page . I recreated this with a very simple example and as far as I can see this just doesn't work anymore.
     

    That's interesting. Can you send your sample to me? My id is mchlsync AT gmail.com. I would like to take a look and will get back to you if I found the solution.

    2. When using usercontrol I would like to use a base class like you can do in WPF (see this post for example: http://geekswithblogs.net/lbugnion/archive/2007/03/02/107747.aspx) but this as well gives me XamlParseException. It's kind of strange because the editor seems to support it fine. It does work if you don't do the xaml bit but then you have to manually change the *g.cs file anytime you do a change.
     

    I tried as below. It works for me.

    1. Create SL project.
    2. MyUserControlBase.cs
    3. Inherits from UserControl

      namespace SL2Test {
          public class MyUserControlBase : UserControl {
              public string DoSomething() {
                  return "Ahh! bad attemps!";
              }
          }
      }


    4. In Page.xaml.cs

      namespace SL2Test {
          public partial class Page : MyUserControlBase {
              public Page() {
                  InitializeComponent();

              }

          }
      }


    5. In Page.xaml,

      <MyUserControlBase x:Class="SL2Test.Page"
          xmlns="http://schemas.microsoft.com/client/2007"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          Width="400" Height="300">
          <Canvas Width="400" Height="300" Background="Red">
          </Canvas>
      </MyUserControlBase>

     

    Saturday, March 08, 2008 12:57 AM
  • Hey.

    Thanks for your quick reply. I will give the namespace thing another try. It's 5am and I am getting quite tired so that might be why ;)

    I sent you an example on the nesting resources problem.

    Thanks,

    -Thomas-

     

    Saturday, March 08, 2008 2:00 AM
  • Re 2: You are right. That does seems to work the way you explained. However my problem is that I have my baseclasses in another namespace (in this case another assembly as well, but it doesn't matter, it errors as soon as you specify namespace).

    So it's something like this:

    <euc:Test1 x:Class="UserControls.Page"
    xmlns=http://schemas.microsoft.com/client/2007
    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
    xmlns:euc="clr-namespace:ExternalUserControl;assembly=ExternalUserControl">
    ...
    </euc:Test1>

    For me that it kind of makes sense that it errors because it doesn't know about the namespace until afterwards.. Or something like that. Though in the example of the before mentioned url that works (in WPF).
    Saturday, March 08, 2008 2:14 AM
  •  Hi,

    I received your mail and also replied to you. It might be something wrong with your project. I have tested with new porject. It's working fine.

    You can download the sample from this link. http://michaelsync.net/demo/SL2TestNestedCtls.zip 

     

    Sunday, March 09, 2008 1:09 AM
  • Hey again.

    Yes, nesting usercontrols works fine, which is what I am doing now (just annoying having to change all the current controls). The problem arises when they are controls with a build action of "embedded resources" and you use the InitializeFromXaml to load in the XAML (please see the example I sent you).

    I have made all the controls that had custom controls inside them to usercontrols to make this work. Only real problem I have now is the second one, having to manually update all the *g.cs files everytime I change a xaml file or if I do a rebuild....

    Cheers,

    -Thomas-

    Sunday, March 09, 2008 3:13 AM
  • oh.  I though you are having the problem with nested controls.

     

    Only real problem I have now is the second one, having to manually update all the *g.cs files everytime I change a xaml file or if I do a rebuild....

    You mean, you can't use like that?

    <MyUserControlBase x:Class="SL2Test.Page"
        xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="400" Height="300">
        <Canvas Width="400" Height="300" Background="Red">
        </Canvas>
    </MyUserControlBase>

     

    Sunday, March 09, 2008 5:50 AM
  • Yes I can. But that limits me to use a class in the same namespace as the control. Since I have loads of controls they are divided in different namespaces and I have one class in another namespace that I want to use as the baseclass. In WPF that works by referencing the namespace with an xmlns.

    Example (app is called SilverlightApplication2):

    BaseClass:
    namespace SilverlightApplication2.AnotherNameSpace
    {
      public class Class1: UserControl
      {}
    }

    Page.xaml.cs:
    public partial class Page : SilverlightApplication2.AnotherNameSpace.Class1
    {
      public Page()
      {
        InitializeComponent();
      }
    }

    Page.xaml (need to add a xmlns to tell it where to find the namespace):
    <test:Class1 x:Class="SilverlightApplication2.Page"
    xmlns:test="clr-namespace:SilverlightApplication2.AnotherNameSpace"
    xmlns=http://schemas.microsoft.com/client/2007
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    </
    test:Class1>

    It works in the designer, it builds fine etc but in InitializeComponent it errors on this line:
    System.Windows.Application.LoadComponent(this, new System.Uri("/SilverlightApplication2;component/Page.xaml", System.UriKind.Relative));

    Error:
    A first chance exception of type 'System.Windows.Markup.XamlParseException' occurred in System.Windows.dll
    Additional information: AG_E_UNKNOWN_ERROR [Line: 6 Position: 95]

    So it seems the application load component doesn't support that xaml syntax.

    Any ideas?

    Thanks,

    -Thomas-

    Sunday, March 09, 2008 6:01 PM
  •  Hi.

     If you want to use "{yourUserControl}.g.cs" for automatic binding xaml object, I don't know how it's possible.

    But if you want to port a 1.1 project to 2.0, there is a simple way.

    Try this.

      1. xaml file's BuildAction must be changed 'SilverlightPage'(or 'EmbededResource') to 'Resource'. 

      2. in 1.1,

             System.IO.Stream s = this.GetType().Assembly.GetManifestResourceStream("{xaml file's path in 1.1 Style}");
             _root = (Canvas)this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd());

         Change this part as follows. 

              System.Windows.Resources.StreamResourceInfo sri = System.Windows.Application.GetResourceStream(new System.Uri("{xaml file's path in 2.0 Style}", System.UriKind.Relative));
                string sXaml = (new System.IO.StreamReader(sri.Stream)).ReadToEnd();
                this._root  = InitializeFromXaml(sXaml) as Canvas;

       and I make a remark about 'xaml file's path'

        in 1.1 ->   '{namespace}.{filename}.xaml'

        in 2.0 -> '/{assemblyname}; component/{subdirectory}/{filename}.xaml'   

       If you change like this, you cannot use auto-generation of xaml object. So you must manually bind all xaml object to use, as you did in 1.1 alpha. 

       but you don't need to update all the *g.cs files everytime.

      

      I hope that this answered your question. Good luck!

      

    Monday, March 10, 2008 10:15 AM
  • Hello, there're some issues related to UserControl inheriting that we're investigating... I'm surprised to see this works:

    <MyUserControlBase x:Class="SL2Test.Page"
        xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="400" Height="300">
        <Canvas Width="400" Height="300" Background="Red">
        </Canvas>
    </MyUserControlBase>

    Actually it shouldn't work. MyUserControlBase is not in the namespace http://schemas.microsoft.com/client/2007. This xml namespaces maps to a series of clr namespaces such as System.Windows.Controls. But there's no way it can map to your own namespace. Also this behavior is inconsistent with WPF.

    This is likely to be a bug. I'll redirect this to our product team. Thanks for letting us know.

     

    Tuesday, March 11, 2008 12:32 AM
  • 'm surprised to see this works:
     

    :)  The solution that I found is breaking the SL rules? :) How can we add our own namespace to  http://schemas.microsoft.com/client/2007?

    Tuesday, March 11, 2008 1:39 AM
  • You're right. This can be a work round.

    In the class library project's AssemblyInfo.cs file, add this:

    [assembly: XmlnsDefinition("http://schemas.microsoft.com/client/2007", "YourNamespace")]

    Now after you add reference to this assembly in your main project, you can use any classes in this namespace in your XAML files.

    But without the namespace mapping, your original code should not work. So this still seems to be an issue...

    Tuesday, March 11, 2008 2:03 AM
  • Guntae Park: Thanks. Though that still doesn't seems to sort my nesting problems. The only I could find to fix that was making all the 1.1 controls that had controls inside them into UserControls.

    Yi-Lun Luo: That's works! It's a bit nasty but beats having to change the *.g.cs file everytime. Thanks for that!

    Thanks all,

    -Thomas-

    Tuesday, March 11, 2008 8:17 AM
  • Guntae Park: Thanks. Though that still doesn't seems to sort my nesting problems. The only I could find to fix that was making all the 1.1 controls that had controls inside them into UserControls.
     

    Sorry, Thomas. I'm a lit bit busy with using Web service and  Astoria in Silverlight. I will take a look the issue now.. I hope it should work. otherwise, Yi-Lun can help us too.

    Tuesday, March 11, 2008 8:24 AM
  • Hey Michael,

    Thanks for that. However; I have already made my controls into usercontrol so I don't need a fix for that anymore. You might want to wait and see if anyone else have that problem before spending more time on it.

    Apriciate your help.

    -Thomas-

    Tuesday, March 11, 2008 8:31 AM
  • Did anyone ever find a solution to the nested controls issue?

    I'm in the same situation. Had a 1.1 app, that uses nested controls, and I get XamlParseExceptions in 2.0.

    Anyone fixed this?

    What about Canvas? Should I use UserControl instead, as the first element in my controls' xaml file?

    Friday, March 28, 2008 6:56 AM
  • I just tested with nested control. The way that I mentioned earlier is working. Actually, the problem that we were having is not the nested control issue. The problem is about putting Base Class in different namespace.

    I posted the sample in this link (http://michaelsync.net/2008/03/24/silverlight-2-beta1-user-control-inheritance) but I didn't put the base control in different namespace. If you want this, please change as below based on the sample from the link above.

    1. Change BaseControl.cs

    namespace SL2Controls.Anothernamespace {
        public class BaseControl : UserControl {

        }
    }
     

    2. update assemblyinfo

    [assembly: XmlnsDefinition("http://schemas.microsoft.com/client/2007", "SL2Controls.Anothernamespace")]

    3. Update InheritedControl.xaml.cs

    public partial class InheritedControl : SL2Controls.Anothernamespace.BaseControl {
            public InheritedControl() {
                InitializeComponent();
            }
        }

    OR

    Add using SL2Controls.Anothernamespace; 

    4.  Update InheritedControl.g.cs

     public partial class InheritedControl : SL2Controls.Anothernamespace.BaseControl {

    OR

    using SL2Controls.Anothernamespace; 

    Updating the generated file is suck but we have no other way to do that.  If you run the sample, you will see it works. if you edit the XAML file, you won't need to modify the generated file. It's strange thing.

    Friday, March 28, 2008 1:02 PM
  • There is a workaround if you want to inherit from a "BaseControl" class in another namespace without having to update the generated ".g.cs" file.  This hack is to include the base control's namespace in a resource.  This works because the autogenerated file adds a "using" statement for any namespace referenced in the Resources.

    To apply this workaround, use Michael's steps #1, #2, and #3 (from the previous post). Instead of editing the generated file (step #4), add a reference to the clr-namespace, and then use this namespace in the Resources. 

    1. <BaseControl x:Class="SL2Controls.InheritedControl"  
    2. xmlns="http://schemas.microsoft.com/client/2007"  
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
    4. Width="400" Height="300"
    5. xmlns:basecontrol="clr-namespace:SL2Controls.Anothernamespace"  
    6. > 
    7. <BaseControl.Resources>
    8. <basecontrol:anyclass x:Name="anyname" />
    9. </BaseControl.Resources>

     

    Saturday, May 10, 2008 6:02 PM
  • Instead of editing the generated file (step #4), add a reference to the clr-namespace, and then use this namespace in the Resources. 
     

    It doesn't work. If you close all file before re-building the application, you won't get any error. but if you open that XAML file and re-build, you will get 3 errors. 

    Warning    1    The tag 'Class1' does not exist in XML namespace 'http://schemas.microsoft.com/winfx/2006/xaml/presentation'.    C:\Michael Sync\MyTechRoom\Silverlight\SL2Beta2\TestApp\TestApp\TestApp\SilverlightControl1.xaml    1    2    TestApp

    Warning    2    The property 'Resources' does not exist on the type 'Grid' in the XML namespace 'http://schemas.microsoft.com/winfx/2006/xaml/presentation'.    C:\Michael Sync\MyTechRoom\Silverlight\SL2Beta2\TestApp\TestApp\TestApp\SilverlightControl1.xaml    7    10    TestApp

    Error    3    Invalid XmlnsDeclaration occurs in assembly 'TestApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. XmlnsDeclaration references a namespace 'TestLibrary2' that is not in the assembly.    C:\Michael Sync\MyTechRoom\Silverlight\SL2Beta2\TestApp\TestApp\TestApp\SilverlightControl1.xaml    1    1    TestApp

    Error    4    The type 'Class1' was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built.    C:\Michael Sync\MyTechRoom\Silverlight\SL2Beta2\TestApp\TestApp\TestApp\SilverlightControl1.xaml    1    2    TestApp

    Error    5    The attachable property 'Resources' was not found in type 'Class1'.    C:\Michael Sync\MyTechRoom\Silverlight\SL2Beta2\TestApp\TestApp\TestApp\SilverlightControl1.xaml    7    10    TestApp

    Saturday, August 23, 2008 12:07 PM
  •  Okay. I got it.

    Please check-out the completed code from this link. 

    http://silverlight.net/forums/p/23213/83217.aspx#83217

    Saturday, August 23, 2008 4:38 PM