locked
Using classes with clause "where" at Visual Studio 2012 RRS feed

  • Question

  • Hello,

    I'am migrating a c# solution from Visual Studio 2010 to 2012.

    I use an specificic UserControl with a "where" clause. The code is:

    namespace CommonUserControls

    {

    public class CMyObject
        {
            public int x;
            public int y;
        }

        public class CMyUserControl<T> : UserControl
            where T : CMyObject
        {
            public CMyUserControl()
            {
            }

        }

    }

    I can use the CMyUserControl in a different assembly, in a XAML file as a User Control:

    <src:CMyUserControl  x:TypeArguments="local:CMyObject"                         
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 xmlns:src="clr-namespace:CommonUserControls;assembly=CommonUserControls"
                 d:DesignHeight="700" d:DesignWidth="700">
        
    </src:CMyUserControl>

    or into other user control:

    <UserControl x:Class="Test.UserControl1"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 xmlns:src="clr-namespace:CommonUserControls;assembly=CommonUserControls"
                 mc:Ignorable="d"
                 d:DesignHeight="300" d:DesignWidth="300">
        <Grid>
                <src:CMyUserControl ... />
        </Grid>
    </UserControl>

    With Visual Studio 2010 this code works fine, but with Visual Studio 2012 I can't use the CMyUserControl into a XAML file. When I use it I get an error message: "The name "CMyUserControl" does not exists in the namespace "clr-namespace:CommonUserControls;assembly=CommonUserControls".

    Within the same assembly de CMyUserControl Intellisense shows, in a XAML file, the user control as "CMyUserControl'1"; obviously CMyUserControl'1 is not a valid name and doesn't works.

    So the question is, how can I use a class with the clause "where" in a XAML file?

    Wednesday, October 10, 2012 6:53 PM

Answers

  • Hi,

    The visual studio 2012 "designer" might not like the 'x:TypeArguments' attribute, but it does compile and run the application.

    However, ONLY A ROOT ELEMENT CAN SPECIFY THE "x:TypeArguments" ATTRIBUTE.

    Whether you use visual studio 2012 or 2010, the runtime rules are the same.

    You can use a generic control as a base class, but not as a standalone control inside another control or page. (Just like you can't use abstract classes directly without an implementation)

    And the reason is because of the error above. If you could specify the x:TypeArguments on any element, I think it would have worked.

    The code below works as a BASE CLASS of a NEW CONTROL: (generic control with an INT32 generic type argument)

    <src:GenericUserControl
      x:Class="WpfApplication6.MyUserControl"
      x:TypeArguments="sys:Int32"
      xmlns:sys="clr-namespace:System;assembly=mscorlib"
      xmlns:src="clr-namespace:WpfApplication6"
    
        
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      >
    </src:GenericUserControl>

    But it won't work as a control TAG inside another control, so the 2nd control won't work:

    <Window 
        x:Class="WpfApplication6.MainWindow"
        xmlns:src="clr-namespace:WpfApplication6"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
            
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
        
            <!--USAGE 1 "IMPLMENTATION" WORKS-->
            <src:MyUserControl Background="Green" />
            
            <!--USAGE 2 "OPEN or ABSTRACT CLASS" NOT WORKING-->
            <src:GenericUserControl x:TypeArguments="sys:Int32" Background="Yellow" Grid.Row="1" />
        </Grid>
    </Window>

    The generic control used for these examples looks like this:

    using System.Windows.Controls;
    
    namespace WpfApplication6 {
    
        public class GenericUserControl<T> : UserControl where T : struct {
    
        }
    }

    Generic types are considered "open" or abstract unless their type arguments are committed inside another type declaration, i.e. the "concrete" class.

    Hopefully that helps to understand it a little bit better.


    Thursday, October 18, 2012 9:00 AM
  • You can't use generics directly from xaml like this.  You would need to make a concrete class that derives from your generic class, and reference it, ie:

    public class MyUserControlFoo : CMyUserControl<Foo>
    {
    
    }

    You could then reference the MyUserControlFoo class from within xaml.


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Thursday, October 11, 2012 6:18 PM
    Moderator

All replies

  • You can't use generics directly from xaml like this.  You would need to make a concrete class that derives from your generic class, and reference it, ie:

    public class MyUserControlFoo : CMyUserControl<Foo>
    {
    
    }

    You could then reference the MyUserControlFoo class from within xaml.


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Thursday, October 11, 2012 6:18 PM
    Moderator
  • Hi argonte

    I agree with Reed. As far as I know you couldn't use GENERIC controls directly in xaml, but you say that it worked in visual studio 2010, and you specify a "x:TypeArguments" attribute that I'm not sure about. It must be new. Never mind that.

    You also mention that "within the same assembly" the intellisense works, so make sure that the xml namespace within the SAME assembly doesn't include the "assembly=thisassembly" part. When the namespace points to the current assembly, you simply use xmlns:xxx="clr-namespace:MyNamespace", without the "assembly=xxx" part.

    Hope that helps to resolve the control reference from the xaml.

    Thursday, October 11, 2012 7:25 PM
  • Hi Reed,

    Yes, with Visual Studio 2012 it's seems the unique solution is to use other class as you propose.

    However with Visual Studio 2010 my code works without problem.

    Friday, October 12, 2012 1:14 PM
  • Hi Martin,

    Yes, with Visual Studio 2010 my code works perfectly.

    Well, at the same assembly intellisense shows the class but finished in "'1"  and I can't use it with o without the "'1".

    In other assemblies I use the name of the namespace without the assembly part as you say but it doesn't work.

    Regards,

    Friday, October 12, 2012 7:06 PM
  • Did you got the solution? I encounter a some like similar question here:http://social.msdn.microsoft.com/Forums/en-US/msbuild/thread/6d348d5e-d918-4370-aaf5-7562468aca16
    Wednesday, October 17, 2012 9:23 AM
  • I didn't get the solution. I'm using an auxiliar class as Reed Copsey, Jr suggested.

    It's not a very ellegant solution but at least I can compile the solution.

    Wednesday, October 17, 2012 6:32 PM
  • It would be wonderful if that "x:TypeArguments" actually worked. I use VS2010 and I didn't know it could be done. It's at least awckward that such a feature disappears in the following version of VS.

    João Miguel

    Wednesday, October 17, 2012 6:54 PM
  • Hi,

    The visual studio 2012 "designer" might not like the 'x:TypeArguments' attribute, but it does compile and run the application.

    However, ONLY A ROOT ELEMENT CAN SPECIFY THE "x:TypeArguments" ATTRIBUTE.

    Whether you use visual studio 2012 or 2010, the runtime rules are the same.

    You can use a generic control as a base class, but not as a standalone control inside another control or page. (Just like you can't use abstract classes directly without an implementation)

    And the reason is because of the error above. If you could specify the x:TypeArguments on any element, I think it would have worked.

    The code below works as a BASE CLASS of a NEW CONTROL: (generic control with an INT32 generic type argument)

    <src:GenericUserControl
      x:Class="WpfApplication6.MyUserControl"
      x:TypeArguments="sys:Int32"
      xmlns:sys="clr-namespace:System;assembly=mscorlib"
      xmlns:src="clr-namespace:WpfApplication6"
    
        
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      >
    </src:GenericUserControl>

    But it won't work as a control TAG inside another control, so the 2nd control won't work:

    <Window 
        x:Class="WpfApplication6.MainWindow"
        xmlns:src="clr-namespace:WpfApplication6"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
            
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
        
            <!--USAGE 1 "IMPLMENTATION" WORKS-->
            <src:MyUserControl Background="Green" />
            
            <!--USAGE 2 "OPEN or ABSTRACT CLASS" NOT WORKING-->
            <src:GenericUserControl x:TypeArguments="sys:Int32" Background="Yellow" Grid.Row="1" />
        </Grid>
    </Window>

    The generic control used for these examples looks like this:

    using System.Windows.Controls;
    
    namespace WpfApplication6 {
    
        public class GenericUserControl<T> : UserControl where T : struct {
    
        }
    }

    Generic types are considered "open" or abstract unless their type arguments are committed inside another type declaration, i.e. the "concrete" class.

    Hopefully that helps to understand it a little bit better.


    Thursday, October 18, 2012 9:00 AM
  • Hello Martin,

    Your code works in Visual Studio 2010 and 2012.

    But in the designer of Visual Studio 2012, MyUserControl.xmal appers as Invalid Markup with the following errors:

    Error    1    The name "GenericUserControl" does not exist in the namespace "clr-namespace:WpfApplication6".    D:\WPF\WpfApplication6\WpfApplication6\MyUserControl.xaml   
    Error    2    The property "TypeArguments" does not exist in the "http://schemas.microsoft.com/winfx/2006/xaml" namespace.    D:\WPF\WpfApplication6\WpfApplication6\MyUserControl.xaml  

    So, although I can use the MyUserControl in Visual Studio 2012 I can't view the content of the control at the Design.

    If I compile my solution with Visual Studio 2012 my application crashed, so I supposed the problem was the use of the "where" clause in an UserControl; I'll have to find the reason of the crash.

    Regards,

    Saturday, October 20, 2012 6:24 PM
  • Why do you think it is the where clause? It might be the fact that you use a generic class directly in XAML. I mean, it seems like so by the error. Have you tried not to use the where clause and watch if you get the error?

    João Miguel

    Tuesday, October 23, 2012 3:32 PM
  • I thought the problem was the "where" clause because in the design (XAML) appears marked as error and my application crashes at the XAML.
    Tuesday, October 23, 2012 6:57 PM
  • I thought that what appeared marked as error was the TypeArguments property. Doesn't that mean the generics itself is not accepted?

    João Miguel

    Tuesday, October 23, 2012 7:02 PM
  • The generic works; the problem appears only in the XAML (in the designer).
    Tuesday, October 23, 2012 7:10 PM
  • Error    2    The property "TypeArguments" does not exist in the "http://schemas.microsoft.com/winfx/2006/xaml" namespace.    D:\WPF\WpfApplication6\WpfApplication6\MyUserControl.xaml

    Perhaps you misunderstood my point; the error as shown above, is the TypeArguments property, which, I believe, specifies the type argument of the user control. As the error does not appear in any way connected to the code itself, there's no reason to think whatsoever that the problem is with the 'where' clause.

    As Reed Copsey and Martin Lottering have shown to me and to you, the designer "doesn't like" such property unless it is applied to a root element, so you'll have to use a helper class.

    Thereby, when I said the genrics doesn't work, I meant that it is not accepted in that context, XAML; as the TypeArguments property which is used for generics in XAML doesn't work with your user control.

    I hope I've made myself clear.


    João Miguel

    Wednesday, October 24, 2012 7:54 PM