I have the following classes:
MainWindow.xaml
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<local:MyControl Margin="8" MyProperty="{Binding MyPropertyParent}" />
</Grid>
MainWindowViewModel.cs
public class MainWindowViewModel : ObservableObject
{
public string MyPropertyParent
{
get
{
return _myProperty;
}
set
{
_myProperty = value;
this.OnPropertyChanged();
}
}
private string _myProperty;
public MainWindowViewModel()
{
MyPropertyParent = "IT WORKS!!!";
}
}
MyControl.xaml
<UserControl.DataContext>
<local:MyControlViewModel/>
</UserControl.DataContext>
<Border CornerRadius="4" Background="White" BorderThickness="1" BorderBrush="#FFB0AEAE">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="#FFC6C6FB">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="4" FontSize="16" VerticalAlignment="Center" HorizontalAlignment="Left"
Text="{Binding MyPropertyHack}" />
</Grid>
</Border>
</Grid>
</Border>
MyControl.xaml.cs
public partial class MyControl : UserControl
{
public string MyProperty
{
get { return (string)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register(
nameof(MyProperty),
typeof(string),
typeof(MyControl),
new PropertyMetadata(null, MyPropertyPropertyChanged));
private static void MyPropertyPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((MyControl)o)._viewModel.MyPropertyHack = (string)e.NewValue;
}
public MyControlViewModel _viewModel;
public MyControl()
{
InitializeComponent();
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
return;
_viewModel = App.Provider.GetService<MyControlViewModel>();
this.DataContext = _viewModel;
}
}
MyControlViewModel.cs
public class MyControlViewModel : ObservableObject
{
private string _myPropertyHack;
public string MyPropertyHack
{
get
{
return _myPropertyHack;
}
set
{
if (_myPropertyHack != value)
{
_myPropertyHack = value;
this.OnPropertyChanged();
}
}
}
public MyControlViewModel()
{
}
}
I'm trying to get it so MainWindow.xaml can pass a property set in its view model through to the DependencyProperty of MyControl. However, when I run it the TextBlock's Text field is empty and so "IT WORKS!!!" is not being shown on the screen and my breakpoint in MyPropertyPropertyChanged is not being hit.
What am I doing wrong?
You set the DataContext of your MyControl explicitly, which means the following binding of MyProperty will bind to the property MyPropertyParent on an instance of MyControlViewModel, which does not have this property. You can also see this as a binding error in the debug window.
<local:MyControl Margin="8" MyProperty="{Binding MyPropertyParent}" />
If you refernce the parent data context (an instance of MainWindowViewModel) through an ElementName or RelativeSource binding or using Parent, it will work, e.g. here I assume a parent as Window. Replace it with a parent in your control, to check it yourself.
<local:MyControl Margin="8" MyProperty="{Binding DataContext.MyPropertyParent, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
Another note, you set the data context twice, one time in XAML and then in the constructor of the control, which means one will definitely be overridden.
<UserControl.DataContext>
<local:MyControlViewModel/>
</UserControl.DataContext>
public MyControl()
{
InitializeComponent();
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
return;
_viewModel = App.Provider.GetService<MyControlViewModel>();
this.DataContext = _viewModel;
}
In general, you should not set the DataContext manually on a UserControl, but inherit it as usual. As you can see this just introduces errors and breaks data binding. Apart from that, you already define a dependency property for the binding, so it is just redundant.
The expression
MyProperty="{Binding MyPropertyParent}"
is supposed to create a Binding to the MyPropertyParent property of the object in the current DataContext.
While you seem to assume that this is the DataContext object set in the MainWindow, it is actually the DataContext object set in the UserControl's constructor.
You should have noticed a data binding error message in the Output Window in Visual Studio, which tells you that a property named MyPropertyParent could not be found on an object of type MyControlViewModel.
In general, a control should never explicity set its own DataContext, since DataContext-based Bindings like the above won't work as expected.
The view model object assigned to the UserControl's DataContext is unknown to the rest of your application. The application will not be able to communicate with this view model.
It is not clear to me why you need a private VM, but I will assume that you simply did not show some part of the task.
DataContext is a property for use by bindings as the default source.
This property has no other function anymore.
And this property is not the only place where the ViewModel can be set.
For a private ViewModel, it, in principle, is not suitable, as already noted in another answer.
Since it sets the source for the bindings of the properties of the control at the place of its application, which is quite unexpected for any programmer.
One of the acceptable options: set an instance in the DataContext of the main element in UserControl.
<Border x:Name="PART_MainBorder"
CornerRadius="4" Background="White"
BorderThickness="1" BorderBrush="#FFB0AEAE">
<d:Border.DataContext>
<local:MyControlViewModel/>
</d:Border.DataContext>
public MyControl()
{
InitializeComponent();
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
return;
_viewModel = App.Provider.GetService<MyControlViewModel>();
PART_MainBorder.DataContext = _viewModel;
}
Related
I am struggling to get a user control to accept a property from my Data Context object. I don't want to pass just the value; but the instance of the property because I would like to have converters operate on the attributes of the property.
I am very new to the WPF space, I've read many articles and none of them don't address this issue. The reason I'm trying to do this is because I have a calculations class that has many properties that need to be displayed and I don't really want to create a user control for each property or have 2,000 lines of repetitious XAML.
Any insight would be greatly appreciated.
Example Class
public class MyClass
{
[MyAttribute("someValue")]
public string Foo { get; set; }
}
View Model
public class MyViewModel : INotifyPropertyChanged
{
private _myClass;
public MyClass MyClass1
{
get => _myClass;
set
{
if(_myClass != value)
{
_myClass = value;
OnPropertyChanged();
}
}
}
}
Parent XAML
<UserControl DataContext="MyViewModel">
<Grid>
<!-- this is where I'm struggling, I think -->
<uc:MyConsumerControl ObjectProp="{Binding Path=MyClass1.Foo}"/>
</Grid>
</UserControl>
User Control
XAML
<UserControl DataContext={Binding RelativeSource={RelativeSource Mode=Self}}>
<Grid>
<TextBox Text="{Binding ObjectProp}"/>
<TextBlock Text="{Binding Path=ObjectProp, Converter={StaticResource MyAttrConverter}}"/>
</Grid>
</UserControl>
C#
public class MyConsumer : UserControl
{
public MyConsumer { InitializeComponent(); }
public object ObjectProp
{
get => (object)GetValue(ObjDepProp);
set => SetValue(ObjDepProp, value);
}
public static readonly DependencyProperty ObjDepProp =
DependencyProperty.Register(nameof(ObjectProp),
typeof(object), typeof(MyConsumer));
}
First of all, there is a naming convention for identifier fields of dependency properties:
public static readonly DependencyProperty ObjectPropProperty =
DependencyProperty.Register(nameof(ObjectProp), typeof(object), typeof(MyConsumer));
public object ObjectProp
{
get => GetValue(ObjectPropProperty);
set => SetValue(ObjectPropProperty, value);
}
Second, a UserControl that exposes bindable properties must never set its own DataContext, so this is wrong:
<UserControl DataContext={Binding RelativeSource={RelativeSource Mode=Self}}>
The XAML should look like this:
<UserControl ...>
<Grid>
<TextBox Text="{Binding ObjectProp,
RelativeSource={RelativeSource AncestorType=UserControl}}" />
<TextBlock Text="{Binding Path=ObjectProp,
RelativeSource={RelativeSource AncestorType=UserControl}, />
Converter={StaticResource MyAttrConverter}}"
</Grid>
</UserControl>
Finally, this is also wrong, because it only assigns a string to the DataContext:
<UserControl DataContext="MyViewModel">
It could probably look like shown below - although that would again explicitly set the DataContext of a UserControl, but perhaps one that could be considered a top-level view element like a Window or Page.
<UserControl ...>
<UserControl.DataContext>
<local:MyViewModel/>
</UserControl.DataContext>
<Grid>
<uc:MyConsumerControl ObjectProp={Binding Path=MyClass1.Foo}
</Grid>
</UserControl>
I created a small File Browser Control:
<UserControl x:Class="Test.UserControls.FileBrowserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="44" d:DesignWidth="461" Name="Control">
<Grid Margin="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox Margin="3" Text="{Binding SelectedFile}" IsReadOnly="True" TextWrapping="Wrap" />
<Button HorizontalAlignment="Right" Margin="3" Width="100" Content="Browse" Grid.Column="1" Command="{Binding BrowseCommand}" />
</Grid>
</UserControl>
With the following code behind:
public partial class FileBrowserControl : UserControl
{
public ICommand BrowseCommand { get; set; }
//The dependency property
public static DependencyProperty SelectedFileProperty = DependencyProperty.Register("SelectedFile",
typeof(string),typeof(FileBrowserControl), new PropertyMetadata(String.Empty));
public string SelectedFile { get{ return (string)GetValue(SelectedFileProperty);} set{ SetValue(SelectedFileProperty, value);}}
//For my first test, this is a static string
public string Filter { get; set; }
public FileBrowserControl()
{
InitializeComponent();
BrowseCommand = new RelayCommand(Browse);
Control.DataContext = this;
}
private void Browse()
{
SaveFileDialog dialog = new SaveFileDialog();
if (Filter != null)
{
dialog.Filter = Filter;
}
if (dialog.ShowDialog() == true)
{
SelectedFile = dialog.FileName;
}
}
}
And I use it like this:
<userControls:FileBrowserControl SelectedFile="{Binding SelectedFile}" Filter="XSLT File (*.xsl)|*.xsl|All Files (*.*)|*.*"/>
(SelectedFile is Property of the ViewModel of the usercontrol using this control)
Currently the issue is that when I click on Browse, the textbox in the usercontrol is correctly updating, but the SelectedFile property of the viewmodel parent control is not set(no call to the set property).
If I set the Mode of the binding to TwoWay, I got this exception:
An unhandled exception of type 'System.StackOverflowException' occurred in Unknown Module.
So what did I do wrong?
The problem is that you set your UserControl's DataContext to itself in its constructor:
DataContext = this;
You should not do that, because it breaks any DataContext based Bindings, i.e. to a view model instance that is provided by property value inheritance of the DataContext property
Instead you would change the binding in the UserControl's XAML like this:
<TextBox Text="{Binding SelectedFile,
RelativeSource={RelativeSource AncestorType=UserControl}}" />
Now, when you use your UserControl and write a binding like
<userControls:FileBrowserControl SelectedFile="{Binding SelectedFile}" />
the SelectedFile property gets bound to a SelectedFile property in your view model, which should be in the DataContext inherited from a parent control.
Do not ever set DataContext of UserControl inside usercontrol:
THIS IS WRONG:
this.DataContext = someDataContext;
because if somebody will use your usercontrol, its common practice to set its datacontext and it is in conflict with what you have set previously
<my:SomeUserControls DataContext="{Binding SomeDataContext}" />
Which one will be used? Well, it depends...
The same applies to Name property. you should not set name to UserControl like this:
<UserControl x:Class="WpfApplication1.SomeUserControl" Name="MyUserControl1" />
because it is in conflict with
<my:SomeUserControls Name="SomeOtherName" />
SOLUTION:
In your control, just use RelativeSource Mode=FindAncestor:
<TextBox Text="{Binding SelectedFile, RelativeSource={RelativeSource AncestorType="userControls:FileBrowserControl"}" />
To your question on how are all those third party controls done: They use TemplateBinding. But TemplateBinding can be used only in ControlTemplate. http://www.codeproject.com/Tips/599954/WPF-TemplateBinding-with-ControlTemplate
In usercontrol the xaml represents Content of UserControl, not ControlTemplate/
Using this:
<userControls:FileBrowserControl SelectedFile="{Binding SelectedFile}" ...
The FileBrowserControl's DataContext has already been set to itself, therefore you are effectively asking to bind to the SelectedFile where the DataContext is the FileBrowserControl, not the parent ViewModel.
Give your View a name and use an ElementName binding instead.
SelectedFile="{Binding DataContext.SelectedFile, ElementName=element}"
I created a small File Browser Control:
<UserControl x:Class="Test.UserControls.FileBrowserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="44" d:DesignWidth="461" Name="Control">
<Grid Margin="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox Margin="3" Text="{Binding SelectedFile}" IsReadOnly="True" TextWrapping="Wrap" />
<Button HorizontalAlignment="Right" Margin="3" Width="100" Content="Browse" Grid.Column="1" Command="{Binding BrowseCommand}" />
</Grid>
</UserControl>
With the following code behind:
public partial class FileBrowserControl : UserControl
{
public ICommand BrowseCommand { get; set; }
//The dependency property
public static DependencyProperty SelectedFileProperty = DependencyProperty.Register("SelectedFile",
typeof(string),typeof(FileBrowserControl), new PropertyMetadata(String.Empty));
public string SelectedFile { get{ return (string)GetValue(SelectedFileProperty);} set{ SetValue(SelectedFileProperty, value);}}
//For my first test, this is a static string
public string Filter { get; set; }
public FileBrowserControl()
{
InitializeComponent();
BrowseCommand = new RelayCommand(Browse);
Control.DataContext = this;
}
private void Browse()
{
SaveFileDialog dialog = new SaveFileDialog();
if (Filter != null)
{
dialog.Filter = Filter;
}
if (dialog.ShowDialog() == true)
{
SelectedFile = dialog.FileName;
}
}
}
And I use it like this:
<userControls:FileBrowserControl SelectedFile="{Binding SelectedFile}" Filter="XSLT File (*.xsl)|*.xsl|All Files (*.*)|*.*"/>
(SelectedFile is Property of the ViewModel of the usercontrol using this control)
Currently the issue is that when I click on Browse, the textbox in the usercontrol is correctly updating, but the SelectedFile property of the viewmodel parent control is not set(no call to the set property).
If I set the Mode of the binding to TwoWay, I got this exception:
An unhandled exception of type 'System.StackOverflowException' occurred in Unknown Module.
So what did I do wrong?
The problem is that you set your UserControl's DataContext to itself in its constructor:
DataContext = this;
You should not do that, because it breaks any DataContext based Bindings, i.e. to a view model instance that is provided by property value inheritance of the DataContext property
Instead you would change the binding in the UserControl's XAML like this:
<TextBox Text="{Binding SelectedFile,
RelativeSource={RelativeSource AncestorType=UserControl}}" />
Now, when you use your UserControl and write a binding like
<userControls:FileBrowserControl SelectedFile="{Binding SelectedFile}" />
the SelectedFile property gets bound to a SelectedFile property in your view model, which should be in the DataContext inherited from a parent control.
Do not ever set DataContext of UserControl inside usercontrol:
THIS IS WRONG:
this.DataContext = someDataContext;
because if somebody will use your usercontrol, its common practice to set its datacontext and it is in conflict with what you have set previously
<my:SomeUserControls DataContext="{Binding SomeDataContext}" />
Which one will be used? Well, it depends...
The same applies to Name property. you should not set name to UserControl like this:
<UserControl x:Class="WpfApplication1.SomeUserControl" Name="MyUserControl1" />
because it is in conflict with
<my:SomeUserControls Name="SomeOtherName" />
SOLUTION:
In your control, just use RelativeSource Mode=FindAncestor:
<TextBox Text="{Binding SelectedFile, RelativeSource={RelativeSource AncestorType="userControls:FileBrowserControl"}" />
To your question on how are all those third party controls done: They use TemplateBinding. But TemplateBinding can be used only in ControlTemplate. http://www.codeproject.com/Tips/599954/WPF-TemplateBinding-with-ControlTemplate
In usercontrol the xaml represents Content of UserControl, not ControlTemplate/
Using this:
<userControls:FileBrowserControl SelectedFile="{Binding SelectedFile}" ...
The FileBrowserControl's DataContext has already been set to itself, therefore you are effectively asking to bind to the SelectedFile where the DataContext is the FileBrowserControl, not the parent ViewModel.
Give your View a name and use an ElementName binding instead.
SelectedFile="{Binding DataContext.SelectedFile, ElementName=element}"
How to create a general user control using MVVM Light?
All the main views in the application seem to work fine. However, general controls doesn't seem to accept bindings. This is my FileDiplay control. An icon and a TextBlock displaying a filename next to it.
Utilization
In one of the main views, I try to bind a FileName inside an ItemsTemplate of an ItemsControl. Specifying a literal, like FileName="xxx" works fine, but binding doesn't.
<local:FileLink FileName="{Binding FileName}" />
I've been playing around with DependencyProperty and INotifyPropertyChanged a lot. And seemingly there's no way around a DependencyProperty, since it can't be bound otherwise. When using a simple TextBlock instead of this user control, binding is accepted.
I didn't include the locator or the utilizing control in order to avoid too much code. In fact, I think this is a very simple problem that I haven't found the solution for, yet. I do think that having the DataContext set to the ViewModel is correct, since no list binding or real UserControl separation is possible. I've also debugged into the setters and tried the different approaches.
FileLink.xaml
<local:UserControlBase
x:Class="....FileLink"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:..."
mc:Ignorable="d" DataContext="{Binding FileLink, Source={StaticResource Locator}}">
<Grid>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Icon}" Margin="0,0,5,0" />
<TextBlock Text="{Binding FileName}" />
</StackPanel>
</Grid>
</local:UserControlBase>
FileLink.xaml.cs
using System.Windows;
using System.Windows.Media;
namespace ...
{
public partial class FileLink : UserControlBase
{
private FileLinkViewModel ViewModel => DataContext as FileLinkViewModel;
public static DependencyProperty FileNameProperty = DependencyProperty.Register(nameof(FileName), typeof(string), typeof(FileLink));
public ImageSource Icon
{
get
{
return App.GetResource("IconFileTypeCsv.png"); // TODO:...
}
}
public string FileName
{
get
{
return ViewModel.FileName;
}
set
{
ViewModel.FileName = value;
}
}
public FileLink()
{
InitializeComponent();
}
}
}
FileLinkViewModel.cs
using GalaSoft.MvvmLight;
namespace ...
{
public class FileLinkViewModel : ViewModelBase
{
private string _FileName;
public string FileName
{
get
{
return _FileName;
}
set
{
Set(() => FileName, ref _FileName, value);
}
}
}
}
Do not explicitly set the DataContext of your UserControl, because it effectively prevents that the control inherits the DataContext from its parent control, which is what you expect in a Binding like
<local:FileLink FileName="{Binding FileName}" />
Also, do not wrap the view model properties like you did with the FileName property. If the view model has a FileName property, the above binding works out of the box, without any wrapping of the view model.
If you really need a FileName property in the UserControl, it should be a regular dependency property
public partial class FileLink : UserControlBase
{
public FileLink()
{
InitializeComponent();
}
public static readonly DependencyProperty FileNameProperty =
DependencyProperty.Register(nameof(FileName), typeof(string), typeof(FileLink));
public string FileName
{
get { return (string)GetValue(FileNameProperty); }
set { SetValue(FileNameProperty, value); }
}
}
and you should bind to it by specifying the UserControl as RelativeSource:
<local:UserControlBase ...> <!-- no DataContext assignment -->
<StackPanel Orientation="Horizontal">
<Image Source="IconFileTypeCsv.png" Margin="0,0,5,0" />
<TextBlock Text="{Binding FileName,
RelativeSource={RelativeSource AncestorType=UserControl}}" />
</StackPanel>
</local:UserControlBase>
I am attempting to adapt a Windows Metro-style app sample slightly by binding the title text to a property defined in code-behind, but I can't seem to get it to work. Reading the blog post titled Bind from XAML to property defined in code-behind, I am trying out "Solution 1".
Here is my XAML source (simplified):
<UserControl x:Class="... .MainPage" x:Name="UserControlSelf"
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"
d:DesignHeight="768" d:DesignWidth="1366">
<Grid x:Name="LayoutRoot" Style="{StaticResource LayoutRootGridStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid x:Name="TitlePanel">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="BackButton" Click="BackButton_Click" Style="{StaticResource BackButtonStyle}"/>
<TextBlock x:Name="PageTitle" Text="{Binding ElementName=UserControlSelf, Path=Title}" Style="{StaticResource TitleStyle}" Grid.Column="1"/>
</Grid>
</Grid>
</UserControl>
And here is my code-behind (simplified):
public partial class MainPage
{
private string _title;
public MainPage()
{
_title = "Test";
InitializeComponent();
}
public string Title
{
get
{
return _title;
}
}
//...
}
I set a breakpoint on the line return _title; in the getter of the Title property. When I debug the app, I see the back button, but the title text block control is blank (no text) and the breakpoint is not triggered:
I set a breakpoint in the autogenerated C# code for the XAML file and verified that UserControlSelf is identical to this within InitializeComponent().
How do I bind the Text of the title text block control to the Title property defined in code-behind?
Can't test Metro app right now, but maybe you should implement INotifyPropertyChanged so the binding can work.
In your code behind:
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public string Title
{
get
{
return this._title;
}
set
{
if (this._title != value)
{
this._title = value;
NotifyPropertyChanged("Title");
}
}
}
Also change
_title = "Test";
to
this.Title = "Test";
I was finally able to get it working. Instead of messing around with ElementName and Path, I simply set the MainPage instance's DataContext to an object other than the MainPage instance that had a Title property. I then changed the Text attribute of the title text block to {Binding Title}.
It does not appear to be necessary for the data context object to implement Windows.UI.Xaml.Data.INotifyPropertyChanged; however, by doing so, the binding automatically behaves like a "one way" binding.
I originally tried setting this.DataContext = this;, but, as I found out, that does not work. If I set it to a POCO or view model instance, then the binding is established.
It would be interesting to know why this.DataContext = this; is erroneous, but at least I can now proceed.
I've not used Metro, but in WPF, that won't work because Title needs to be a Dependency Property. Change your code behind like this:
public partial class MainPage
{
public static readonly DependencyProperty TitleProperty;
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
static MainPage()
{
TitleProperty= DependencyProperty.Register(
"Title",
typeof(string),
typeof(MainPage));
}
public MainPage()
{
InitializeComponent();
Title = "Test";
}
}
This caught me out yesterday, it's so easy to forget to do.
This technique always works for me
Text="{Binding ElementName=LayoutRoot, Path=Parent.Title}"
This assumes that the user control’s child element name is “LayoutRoot” which it is by default.