views:

2471

answers:

2

Hello!

I'm using the lastest version of Silverlight 2.0 within Visual Studio 2008. I have a simple Silverlight UserControl with the following code:

  public partial class SilverlightControl1 : UserControl
  {
    public SilverlightControl1()
    {
      InitializeComponent();
      this.Loaded += new RoutedEventHandler(SilverlightControl1_Loaded);
      Composite = new Composite();
    }

    void SilverlightControl1_Loaded(object sender, RoutedEventArgs e)
    {
      Composite.Width = this.Width / 2.0;
      Composite.Height = this.Height / 2.0;
      if (!this.LayoutRoot.Children.Contains(Composite)) this.LayoutRoot.Children.Add(Composite);
    }

    public Composite Composite
    {
      get;
      set;
    }
  }

  public class Composite : ContentControl
  {
    private Grid grid;
    private Canvas canvas;

    public Composite()
    {
      if (grid == null) grid = new Grid();
      if (canvas == null) canvas = new Canvas();
      if (!grid.Children.Contains(canvas)) grid.Children.Add(canvas);
      Content = grid;
      this.Loaded += new RoutedEventHandler(Composite_Loaded);
    }

    private Rectangle rectangle;

    void Composite_Loaded(object sender, RoutedEventArgs e)
    {
      if (rectangle == null) rectangle = new Rectangle();
      Canvas.SetTop(rectangle, 0);
      Canvas.SetLeft(rectangle, 0);
      rectangle.Fill = new SolidColorBrush(Color);
      rectangle.Width = Width;
      rectangle.Height = Height;
      if (!canvas.Children.Contains(rectangle)) canvas.Children.Add(rectangle);
    }

    public Color Color
    {
      get;
      set;
    }
  }

I then use this UserControl in a Silverlight application, the XAML of the page looking like this:

<UserControl x:Class="SilverlightApplication1.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:test="clr-namespace:SilverlightClassLibrary1;assembly=SilverlightClassLibrary1"
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="Green">
    <test:SilverlightControl1 Name="uControl1">
      <test:SilverlightControl1.Composite>
        <test:Composite Color="Yellow"/>
      </test:SilverlightControl1.Composite>
    </test:SilverlightControl1>
    </Grid>
</UserControl>

My question is: what code do I have to add to the above so that by changing "Composite Color" to something other than Yellow and hitting the return button, the UserControl automatically refreshes? As the code is, the only way to refresh the UserControl is by moving the Slider bar within the VS2008 IDE which changes the percentage zoom of the Silverlight Page. A side question, although of lesser importance to the above question, is: with the code as it is above, why can't I change the "Background" color of the LayoutRoot? If I remove my UserControl it works as expected.

Many thanks for any pointers which help me understand what is going on here!

A: 

I think you need to make Composite into a Dependency Proprety. Probably will want to do the same thing for Color on Composite so that you'll be able to bind it.

Correl
Thanks for the answer, Correl! I've implemented the Composite and Color properties as Dependency properties, as you suggested, but unfortunately this hasn't made any difference to the problem!
Shunyata Kharg
Looking at the code, I think the problem here is that you are setting the color in the OnLoaded events. When you are changing the color, you're not forcing VS to reload the control, so that event isn't fired again. Instead of setting the Fill of the Rectangle to the value of Color, try binding it instead. That way when the Color changes, the Dependency property fires and updates it.
Correl
Thanks Correl! I have the Color property implemented as a Dependency property using DependencyObject.GetValue and SetValue. When I set the fill of the Rectangle, the Color property is therefore already binded to the dependency property, no?
Shunyata Kharg
Not quite. To actually bind it, you need to create a binding. Try the following code instead of using rectangle.Fill = new SolidColorBrush(Color):Binding binding = new Binding();binding.Source = this;binding.Path = new PropertyPath("Color");rectangle.SetBinding(Rectangle.FillProperty, binding);
Correl
A: 

The solution was two-fold. Firstly to make changes in the LayoutUpdated event rather than the Loaded event and secondly to subscribe to the PropertyChangedCallback of the PropertyMetadata. Here's the complete working code:

  public partial class SilverlightControl1 : UserControl
  {
    public SilverlightControl1()
    {
      InitializeComponent();
      this.LayoutUpdated += new EventHandler(SilverlightControl1_LayoutUpdated);
      Composite = new Composite();
    }

    void SilverlightControl1_LayoutUpdated(object sender, EventArgs e)
    {
      Composite.Width = this.Width / 2.0;
      Composite.Height = this.Height / 2.0;
      if (!this.LayoutRoot.Children.Contains(Composite)) this.LayoutRoot.Children.Add(Composite);
    }

    public Composite Composite
    {
      get;
      set;
    }
  }

  public class Composite : ContentControl
  {
    private Grid grid;
    private Canvas canvas;

    public Composite()
    {
      if (grid == null) grid = new Grid();
      if (canvas == null) canvas = new Canvas();
      if (!grid.Children.Contains(canvas)) grid.Children.Add(canvas);
      Content = grid;
      this.LayoutUpdated += new EventHandler(Composite_LayoutUpdated);
    }

    void Composite_LayoutUpdated(object sender, EventArgs e)
    {
      if (rectangle == null) rectangle = new Rectangle();
      Canvas.SetTop(rectangle, 0);
      Canvas.SetLeft(rectangle, 0);
      rectangle.Fill = new SolidColorBrush(Color);

      rectangle.Width = Width;
      rectangle.Height = Height;
      if (!canvas.Children.Contains(rectangle)) canvas.Children.Add(rectangle);
    }

    public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Color), typeof(Composite), new PropertyMetadata(Colors.Red, new PropertyChangedCallback(OnColorPropertyChanged)));

    private static void OnColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      Composite comp = (Composite)d;
      comp.InvalidateArrange();
    }

    private Rectangle rectangle;

    public Color Color
    {
      get { return (Color)GetValue(ColorProperty); }
      set { SetValue(ColorProperty, value); }
    }
  }
Shunyata Kharg