tags:

views:

56

answers:

2

I am new to this forum. I have a custom user control defined using c# and xaml. When i dag and drop this control to WPF window it works. Even i can edit xaml code tags and insert my control. But when i use my control in c# code, it dont work.

here is my xaml control definition

<ResourceDictionary
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:local="clr-namespace:UserControl"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;   
  <!-- Resource dictionary entries should be defined here. -->
  <Style TargetType="{x:Type local:WellImage}">
    <Setter Property="Focusable" Value="false" />
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type local:WellImage}">
          <Grid Width="Auto" Height="Auto">
            <Ellipse Stroke="{Binding Path=WellBorder, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
                     StrokeThickness="{Binding Path=WellBorderThickness, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
                     x:Name="Border" Width="Auto" Height="Auto"
                     HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                     Fill="{Binding Path=OuterBackGround, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />
            <Ellipse StrokeThickness="0" Margin="25,37,25,18" RenderTransformOrigin="0.5,0.5"
                     Fill="{Binding Path=InnerBackGround, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>
          </Grid>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>

and here is my c# control definition

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace UserControl
{
  public class WellImage : System.Windows.Controls.Button
  {
    public static readonly DependencyProperty InnerBackGroundProperty = DependencyProperty.Register("InnerBackGround", typeof(RadialGradientBrush), typeof(WellImage));
    public static readonly DependencyProperty OuterBackGroundProperty = DependencyProperty.Register("OuterBackGround", typeof(RadialGradientBrush), typeof(WellImage));
    public static readonly DependencyProperty WellBorderProperty = DependencyProperty.Register("WellBorder", typeof(SolidColorBrush), typeof(WellImage));
    public static readonly DependencyProperty WellBorderThicknessProperty = DependencyProperty.Register("WellBorderThickness", typeof(double), typeof(WellImage));

    public WellImage()
    {
      // Insert code required on object creation below this point.
      InnerBackGround = (RadialGradientBrush)this.Resources["WellSelectedInnerCircleBrush"];
      OuterBackGround = (RadialGradientBrush)this.Resources["WellSelectedOuterCircleBrush"];
      WellBorder = (SolidColorBrush)this.Resources["NormalBackgroundBrush"];
      WellBorderThickness =2;
    }

    static WellImage()
    {
      //This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
      //This style is defined in themes\generic.xaml
      DefaultStyleKeyProperty.OverrideMetadata(typeof(WellImage), new FrameworkPropertyMetadata(typeof(WellImage)));
    }

    public RadialGradientBrush InnerBackGround
    {
      get { return (RadialGradientBrush)GetValue(InnerBackGroundProperty); }
      set { SetValue(InnerBackGroundProperty, value); }
    }

    public RadialGradientBrush OuterBackGround
    {
      get { return (RadialGradientBrush)GetValue(OuterBackGroundProperty); }
      set { SetValue(OuterBackGroundProperty, value); }
    }

    public SolidColorBrush WellBorder
    {
      get { return (SolidColorBrush)GetValue(WellBorderProperty); }
      set { SetValue(WellBorderProperty, value); }
    }

    public double WellBorderThickness
    {
      get { return (double)GetValue(WellBorderThicknessProperty); }
      set { SetValue(WellBorderThicknessProperty, value); }
    }
  }
}

and this is how tried to access this controll via c#

 WellImage image = new WellImage();            
        image.Height = 40; 
        image.Width = 40;
        image.Margin = new Thickness(30, 30, 30, 30);
        image.VerticalAlignment = VerticalAlignment.Top;
        image.HorizontalAlignment = HorizontalAlignment.Left;
        image.Content = "WellButton";
        grid.Children.Insert(0, image);
        grid.Background = Brushes.LightBlue;
        grid.Width = 120;
        grid.Height = 100;
        grid.VerticalAlignment = VerticalAlignment.Top;
        grid.HorizontalAlignment = HorizontalAlignment.Left;
        gridPartialedMicroPlate.Children.Insert(0, grid);

Why i fail to access my control?

A: 

Hello Aaronontheweb; Thank you for the reply. I am not getting any error messages. But i cant see it loading. Thanks Peter

Peter
+2  A: 

You have three main problems:

  1. Your InnerBackground, OuterBackground and WellBorder are always null,
  2. You have no ContentPresenter in your template,
  3. Your ellipses are zero size

Null brushes

The reason InnerBackground, OuterBackground and WellBorder are null is that you set them to null in the constructor. For example this line is a problem:

InnerBackGround = (RadialGradientBrush)this.Resources["WellSelectedInnerCircleBrush"]; 

There are two issues with this line:

  1. It uses this.Resoures[], which only looks in the local ResourceDictionary. To do the equivalent of StaticResource, you must look in your ancestors' ResourceDictionaries which means calling FindResource().
  2. It is in the constructor, so it executes before the control has a parent. Since it has no ancestors at this point, even FindResource() would not work for you.

The best solution to this problem is to set these properties in the Style instead of in the constructor:

<Style TargetType="{x:Type local:WellImage}">
  <Setter Property="Focusable" Value="false" /> 
  <Setter Property="InnerBackground" Value="{DynamicResource WellSelectedInnerCircleBrush}" />
  ...

If you really want to do it in the constructor, you can construct a DynamicResource reference there:

SetValue(InnerBackgroundProperty,
  new DynamicResourceExtension("WellSelectedInnerCircleBrush")
  .ProvideValue());

Missing ContentPresenter

If you had included a ContentPresenter in your template you would have seen the string "WellButton" displayed even though the ellipses would have been invisible.

You should consider modifying your ControlTemplate to include a ContentPresenter to display the Content property. It seems pointless to be assigning the Content property but not displaying it.

Zero-size ellipses

Each Ellipse is set with Width="Auto" Height="Auto", which for an ellipse means zero size. This will make your ellipses invisible even if they have brushes.

Also the grid is set with Width="Auto" Height="Auto", which means to squeeze its contents into the tiniest space possible. This means that if the WellButton is set with VerticalAlignment="Stretch" or HorizontalAlignment="Stretch" it will stubbornly refuse to actually stretch. This is a bad thing in a custom control.

Remove both places where you say Width="Auto" and Height="Auto", and instead leave the Height and Width unset.

Other issues and nitpicks

Your second ellipse has StrokeThickness="0" which makes no sense to me since there is no stroke. Why not leave it out? Ditto for the RenderTransformOrigin since there is no RenderTransform.

Your first ellipse need not specify HorizontalAlignment="Stretch" VerticalAlignment="Stretch" since this is the default.

Your bindings are far too complicated:

  1. You can omit the "Path=" unless the path contains attached properties.
  2. You can omit the "Mode=OneWay" since that is the default, but most importantly:
  3. You can use a TemplateBinding instead which is much cleaner:

TemplateBinding syntax:

<Ellipse Stroke="{TemplateBinding WellBorder}"
         ... />

The margins on your second ellipse are so large that even if the Width="40" Height="40" in your C# code were honored (because the Auto problem was fixed), the Ellipse would still have no size. Also it seems strange to have an ellipse with such an unusual margin.

Nitpick: "Background" is a single English word, and it doesn't have a capital G in the middle.

Ray Burns
Excellent answer!! +1!!
jameschinnock
Yeah its an excellent answer. Thanks Ray.
Peter
@Peter: Glad I could help. By the way, if you think this is the best answer to your question, you should click the checkmark to mark it as the best answer. This gives us both "rep" points, it brings up your "answer %", and it helps others recognize the best answer.
Ray Burns