views:

1848

answers:

2

I have had major problems with getting UserControls to work in XAML - I have spent hours trying to figure out all the problems but have got nowhere and cannot find where I am going wrong.
The main problem I am having is when I create a UserControl for example a simple one which shows an object different colours - I have successfully created a property for this and can assign the colours to this UserControl at Design Time and it works - shows Green, Red etc.
However when I give this UserControl a name so I can assign this Property at Runtime I get an error "Could not create instance of type 'MyUserControl'" if I remove the name the user control works - I can add as many as I want at Design Time and they all work but as soon as I assign a Name or x:Name it breaks and I cannot figure out why.
It is possible to create a Label for example and it has a name I can refer to it in code - why not my own control - no matter how simple.

My main problems are:

  1. Why does giving my UserControl a Name or x:name stop it from working?
  2. How to use multiple UserControls of the same type on a Window?
  3. How to access the Canvas, Label etc of a UserControl from inside or outside the UserControl?
  4. How to instance a UserControl at runtime or at design time in code or XAML?

I don't get why these should be so difficult - I cannot figure out this issue so please if anyone can help then thanks!


Here is the XAML and Code for my UserControl

<UserControl x:Class="Device.Draco"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="20" Height="36" x:Name="Icon">
    <Canvas Width="20" Height="36" HorizontalAlignment="Left" VerticalAlignment="Top">
        <Rectangle Height="36" Width="20" Fill="{Binding ElementName=Icon, Path=ZuneColour}" Canvas.Left="0" Canvas.Top="0" RadiusX="1" RadiusY="1">
            <Rectangle.BitmapEffect><OuterGlowBitmapEffect GlowColor="Black" GlowSize="2" /></Rectangle.BitmapEffect>
        </Rectangle>
        <Rectangle Canvas.Left="1" Canvas.Top="1" Height="24" Stroke="#191616" Width="18">
            <Rectangle.Fill>
                <LinearGradientBrush>
                    <GradientStop Offset="1" Color="#231F20"/>
                    <GradientStop Offset="0" Color="#524F4F"/>
                    <LinearGradientBrush.Transform>
                        <RotateTransform Angle="68" CenterX="0.5" CenterY="0.5"/>
                    </LinearGradientBrush.Transform>
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>
        <Rectangle Canvas.Left="5.5" Canvas.Top="25" Height="9" Width="9" RadiusX="3" RadiusY="3">
            <Rectangle.Fill>
                <LinearGradientBrush>
                    <GradientStop Offset="0" Color="#66000000"/>
                    <GradientStop Offset="1" Color="#22000000"/>
                </LinearGradientBrush>
            </Rectangle.Fill>
            <Rectangle.Stroke>
                <LinearGradientBrush>
                    <GradientStop Offset="0" Color="#66FFFFFF"/>
                    <GradientStop Offset="1" Color="#22FFFFFF"/>
                </LinearGradientBrush>
            </Rectangle.Stroke>
        </Rectangle>
    </Canvas>

This is the code for the UserControl - have added all the styles and fills as simple XAML to eliminate this as the cause - the Code Behind is below:

Namespace Device
    Partial Public Class Draco
        Inherits System.Windows.Controls.UserControl
        Public Shared ZuneColorProperty As DependencyProperty = _
        DependencyProperty.Register("ZuneColour", GetType(Brush), GetType(Device.Draco))
        Public Property ZuneColour() As Brush
            Get
                Return GetValue(ZuneColorProperty)
            End Get
            Set(ByVal Value As Brush)
                SetValue(ZuneColorProperty, Value)
            End Set
        End Property
    End Class
End Namespace

Here is an example of how I use it currently

<Window x:Class="Demo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ui="clr-namespace:ZuneCards.Device"
    Title="Demo" Height="300" Width="300" Name="Window1">
    <Grid>
        <ui:Draco ZuneColour="Pink" HorizontalAlignment="Right" Margin="0,113,81,113" Width="20"></ui:Draco>
    </Grid>
</Window>
+1  A: 

I'm not sure I can solve your specific problems with your UserControl without seeing the source code for it.

I can however answer part 3. If you give a part of a controls template a name, you can retrieve that part from within the controls code. From there you can return it publicly if needed.

<ControlTemplate TargetType="{x:Type l:MyUserControl}">
    <Button x:Name="PART_button">My Button</Button>
</ControlTemplate>

[TemplatePart(Name = "PART_button", Type = typeof(Button))]
public class MyUserControl:UserControl
{

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        Button button = (Button)base.GetTemplateChild("PART_button");

        // do something with the button control
    }

}

The attribute says that this control needs a "PART_button" control of type Button in it's template. Then in the OnApplyTemplate method you can call GetTemplateChild to retrieve the part you need.

Cameron MacFarland
+1  A: 
  1. There is probably something else wrong if adding Name or x:Name causes the UserControl to fail. Moreover, use x:Name over Name.
  2. The following code will use multiple controls:

    <WrapPanel> <ui:Draco ZuneColour="Pink" Width="20" /> <ui:Draco ZuneColour="Red" Width="20" /> <ui:Draco ZuneColour="Orange" Width="20" /> </WrapPanel>

  3. A UserControl is a a class. The XAML for the UserControl is private unless exposed through templating. Therefore unless you provide methods or the consumer of the UserControl overrides the template, they cannot control the innards. The same goes for your UserControl, it can't play with the innards of its parent. If you need that tight of coupling I suggest you not use a UserControl.

  4. Given the following XAML:

    <StackPanel x:Name="ZunePanel" />

You can use the following code behind:

ZunePanel.Children.Add(new Draco());
sixlettervariables
no clue why the code formatting is choking on the XAML.
sixlettervariables
Creating UserControls via Code seems to work just fine - may be a designer issue but thanks
RoguePlanetoid