Mauro
Mauro

Reputation: 319

MVVM Binding to Custom Control in Windows Phone

I have the following simple custom control that I have defined for a Windows Phone Application. The XAML for the control is as follows :

<UserControl x:Class="PhoneApp1.MyControl"
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="480"
         d:DesignWidth="480"
         DataContext="{Binding RelativeSource={RelativeSource Self}}">

<Grid x:Name="LayoutRoot">
    <TextBlock Text="{Binding MyLabel}" />
</Grid>

In addition the user control has a dependency property which looks as follows :

public partial class MyControl : UserControl
{
    public MyControl()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty MyLabelProperty =
        DependencyProperty.Register("MyLabel", typeof (string), typeof (MyControl), new PropertyMetadata(default(string)));

    public string MyLabel
    {
        get { return (string) GetValue(MyLabelProperty); }
        set { SetValue(MyLabelProperty, value); }
    }
}

Now the thing is when I try to databind it to a View Model that I have created, nothing happens. The various code items are as follows :

public class MyControlViewModel : ViewModelBase
{
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value;
        RaisePropertyChanged(() => Name);}
    }
}

View Model declare in App.xaml

<Application.Resources>
    <PhoneApp1:MyControlViewModel x:Key="MCVM" />
</Application.Resources>

MainPage.xaml declaration of the control

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <PhoneApp1:MyControl  x:Name="testControl" DataContext="{StaticResource MCVM}" MyLabel="{Binding Path=MyLabel}" />            
    </Grid>

However, if I try to databind it to some other UI Element as follows,it seems to work?

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <PhoneApp1:MyControl  x:Name="testControl" MyLabel="{Binding ElementName=Button, Path=Content}" />
        <Button Click="Button_Click" x:Name="Button" Content="Click" />
    </Grid>

I have been struggling to get this simple scenario to work, and I think that there is something silly that I'm missing?

Any help would be greatly appreciated

Upvotes: 3

Views: 1009

Answers (1)

user1228
user1228

Reputation:

(This is WPF; I'm not sure if this isn't 100% analogous to WP7 silverlight; I provide further details to help you understand what's going on so that you may research a proper solution if my two options aren't available)

By default, bindings are rooted at the DataContext of the root element of the xaml file (be it a Window or a UserControl). That means that

<TextBlock Text="{Binding MyLabel}" />

attempts to bind to the DataContext. So, essentially, the property you are attempting to bind against is

MyControl.DataContext.MyLabel

You need to bind to the following instead:

MyControl.MyLabel

So, you must rebase the binding to the element in the visual tree you wish to bind against, the MyControl class. You can do this a few ways...

<TextBlock Text="{Binding MyLabel, 
                 RelativeSource={RelativeSource FindAncestor,
                                                AncestorType=UserControl}" />

is common, but that has to walk the tree and can cause some performance issues. I find it easier, and recommend, to do the following:

<UserControl x:Class="PhoneApp1.MyControl"
             x:Name="root"
             x:SnipAttributesBecauseThisIsAnExample="true">
    <TextBlock Text="{Binding MyLabel, ElementName=root}" />
</UserControl>

Give your UserControl a Name, then use ElementName to rebase your binding to the root of the visual tree.

I'll leave out the other, wackier ways to accomplish this.

Upvotes: 5

Related Questions