WP7: problemas de enlace con UserControl

A medida que desarrollo mi aplicación, descubro que estoy recreando un control de "mosaico" con demasiada frecuencia. Por lo tanto, actualmente estoy tratando de moverlo a un Control de usuario para volver a usarlo. Sin embargo, actualmente no acepta ningún enlace que funcionaba anteriormente. Así por ejemplo:

<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>

Funciona bien con las fijaciones,

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

produce el error "el parámetro es incorrecto".

Aquí está el código para mi Tile UserControl:

Mosaico.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;
            }
        }
    }
}

Si necesita alguna fuente más, hágamelo saber y lo publicaré. No tengo ningún problema cuando uso un valor fijo (Height y Width están bien, y si pongo Background a Red entonces eso también funciona bien), pero cambiar a un valor Binding arroja la excepción.


EDIT 1

Aquí hay un código actualizado:

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;
        }
    }

}

También estoy comparando los dos métodos uno al lado del otro. El mosaico de la izquierda es el lienzo definido con enlaces en pleno funcionamiento, mientras que el mosaico de la derecha es el control de usuario de mosaico, que solo funciona con colores definidos (azul en este caso)

Captura de pantalla

preguntado el 03 de mayo de 12 a las 18:05

1 Respuestas

Para poder enlazar en XAML no basta con crear una propiedad. Tienes que crear un DependenciaPropiedad.

La razón por la que tu Background obras vinculantes, es que UserControl tiene esta propiedad. Si establece un punto de interrupción en su Background setter de propiedad, verás que nunca se llama.

Aquí hay un ejemplo de un DependencyProperty para su Background (no probado)

#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

contestado el 23 de mayo de 17 a las 13:05

¿Algún tutorial que puedas recomendar sobre esto? Mis intentos de implementar esto han llegado a nada hasta ahora. - Michael Dodd

vea la edición, para las otras propiedades solo tiene que cambiar los nombres y tipos - pulgarcitos

Ha funcionado para el Icono. Todavía estoy tratando de hacerlo funcionar con el fondo. - Michael Dodd

para el fondo, realmente no lo necesita, ya que el control de usuario tiene esta propiedad de todos modos. Simplemente elimine rectBackground de su xaml - pulgarcitos

Eliminar rectBackground y usar la propiedad de fondo integrada de UserControl no funciona. Curiosamente, si cambio el nombre de la propiedad a TileBG y uso un color definido, el método rectBackground funciona bien. Sin embargo, todavía se cae al encuadernarlo. Ver Edición 1 para mi código actual. - Michael Dodd

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.