0

As I'm developing my app, I'm finding that I'm re-creating a "tile" control far too often. Therefore I'm currently trying to move it into a User Control for re-use. However, it's currently not accepting any bindings that were previously working. So for example:

<Canvas Height="73" Width="73" VerticalAlignment="Top" Margin="10,10,8,0">
    <Rectangle Height="73" Width="73" VerticalAlignment="Top" Fill="{Binding Path=Active, Converter={StaticResource IconBackground}}" />
    <Image Height="61" Width="61" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="6"  Source="{Binding Tone.Image}" />
</Canvas>

Works fine with the bindings,

<views:Tile Height="73" Width="73" Background="{Binding Path=Active, Converter={StaticResource IconBackground}, Mode=OneWay}" Icon="{Binding Path=Tone.Image, Mode=OneTime}" />

produces the error "the parameter is incorrect".

Here is the code for my Tile UserControl:

Tile.xaml

<UserControl x:Class="RSS_Alarm.Views.Tile"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="100" d:DesignWidth="100">

    <Grid x:Name="LayoutRoot">
        <Canvas Height="100" Width="100" Margin="0,0,0,0">
            <Rectangle Name="rectBackground" Height="100" Width="100" />
            <Image Name="imgIcon" Height="80" Width="80" VerticalAlignment="Center" HorizontalAlignment="Center" Canvas.Left="10" Canvas.Top="10" />
        </Canvas>
    </Grid>
</UserControl>

Tile.xaml.cs

namespace RSS_Alarm.Views
{
    public partial class Tile : UserControl
    {
        public Tile()
        {
            InitializeComponent();
        }

        public String Icon
        {
            get
            {
                return imgIcon.Source.ToString();
            }

            set
            {
                BitmapImage alarmIcon = new BitmapImage();
                alarmIcon.UriSource = new Uri(value, UriKind.Relative);
                imgIcon.Source = alarmIcon;
            }

        }

        new public Brush Background
        {
            get
            {
                return rectBackground.Fill;
            }

            set
            {
                rectBackground.Fill = value;
            }
        }

        new public double Height
        {
            get
            {
                return rectBackground.Height;
            }

            set
            {
                rectBackground.Height = value;
                imgIcon.Height = value * 0.8;
            }
        }

        new public double Width
        {
            get
            {
                return rectBackground.Width;
            }

            set
            {
                rectBackground.Width = value;
                imgIcon.Width = value * 0.8;
            }
        }
    }
}

If you need any more source, let me know and I'll post it. I don't have any problems when using a fixed value (Height and Width are fine, and if I set Background to Red then that also works fine), but changing to a Binding value throws the exception.


EDIT 1

Here's some updated code:

Tile.xaml.cs

#region Background
        public static readonly DependencyProperty RectBackgroundProperty =
           DependencyProperty.Register(
               "RectBackground",
               typeof(SolidColorBrush),
               typeof(Tile),
               new PropertyMetadata(new SolidColorBrush(Colors.Green), new PropertyChangedCallback(OnBackgroundChanged))
           );

        public static void OnBackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Debug.WriteLine("Filling background");
            ((Tile)d).rectBackground.Fill = (Brush)e.NewValue;
        }

        new public SolidColorBrush Background
        {
            get { return (SolidColorBrush)GetValue(RectBackgroundProperty); }
            set { 
                Debug.WriteLine("Setting colour"); 
                SetValue(RectBackgroundProperty, value); 
            }
        }
#endregion

MainMenuControl.xaml.cs

// Class to determine the background colour of the icon (active/inactive)
public class IconBackground : System.Windows.Data.IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool b = (bool)value;

        Debug.WriteLine("Converting colour. Value is " + b.ToString());

        if (b)
        {
            return (Brush)App.Current.Resources["PhoneAccentBrush"];
        }
        else
        {
            return new SolidColorBrush(Colors.DarkGray);
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        SolidColorBrush brush = (SolidColorBrush)value;

        if (brush.Color.Equals(Colors.DarkGray))
        {
            return false;
        }
        else
        {
            return true;
        }
    }

}

I'm also comparing the two methods side-by-side. The tile on the left is the defined Canvas with bindings fully working, while the tile on the right is the Tile UserControl, which only works with defined colours (Blue in this case)

Screenshot

1 Answer 1

2

In order to be able to bind in XAML it is not enough to make a property. You have to create a DependencyProperty.

The reason your Background binding works, is that UserControl itself has this property. If you set a breakpoint in your Background property setter, you will see that it is never called.

Here is an example of a DependencyProperty for your Background (not tested)

#region Background
        public const string BackgroundPropertyName = "Background";
        public new Brush Background
        {
            get { return (Background)GetValue (BackgroundProperty); }
            set { SetValue (Background, value); }
        }
        public static new readonly DependencyProperty BackgroundProperty = DependencyProperty.Register (
            BackgroundPropertyName,
            typeof (Brush),
            typeof (Tile),
            new PropertyMetadata (BackgroundChanged));

        static void BackgroundChanged (DependencyObject d, DependencyPropertyChangedEventArgs e)
        {                
            ((Tile) d).rectBackground = (Brush)e.NewValue;    
        }
    #endregion
Sign up to request clarification or add additional context in comments.

7 Comments

Any tutorials you can recommend on this? My attempts to implement this have come to nothing so far.
see the edit, for the other properties you just have to change the names and types
It's worked for the Icon. Still trying to get it working with the background.
for the background you dont really need it, as the usercontrol has this property anyway. Just remove rectBackground from your xaml
Removing rectBackground and using the UserControl's built-in Background property doesn't work. Interestingly, if I rename the property to TileBG and use a defined colour the rectBackground method works fine. However it still falls over on binding. See Edit 1 for my current code.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.