Not getting value when button is clicked - c#

Using data binding to get value from another UserControl when the button is clicked
So, I have a UserControl that is nested in another UserControl that is also nested in the main window, that looks like this,
MainWindow.xaml:
<Window
xmlns:view="clr-namespace:InvoiceAppV2.View"
<Grid>
<TabControl>
<TabItem>
<view:InvoiceControl>
</TabItem>
<TabItem/>
<TabItem/>
</TabControl>
</Grid>
</Window>
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
InvoiceControl xaml:
<UserControl
xmlns:view="clr-namespace:InvoiceAppV2.View"
<Grid>
<view:BuyerInfoControl/>
</Grid>
<Button x:Name="btnSubmit" Content="Submit" Click="BtnSubmit_Click"/>
</UserControl>
InvoiceControl.xaml.cs
public partial class InvoiceControl : UserControl
{
Buyer b = new Buyer();
public InvoiceUserControl()
{
InitializeComponent();
}
private void BtnSubmit_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(b.BuyerName);
}
}
BuyerInfoControl xaml:
<UserControl
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Content="Buyer's Name"/>
<Label Content="Purchase Date"/>
<TextBox x:Name="txtBuyerName" Text="{Binding Path=BuyerName, Mode=TwoWay}"
TextWrapping="NoWrap"/>
<DatePicker x:Name="txtPurchaseDate" Text="{Binding Path=PurchaseDate, Mode=TwoWay}" />
</Grid>
Here's the code to handle the property change
public class Buyer: INotifyPropertyChanged
{
private int _id;
private string _name;
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public int ID
{
get { return _id; }
set { _id = value; }
}
public string BuyerName
{
get { return _name; }
set
{
if(_name != value)
{
_name = value;
PropertyChanged(this, new PropertyChangedEventArgs("BuyerName"));
}
}
}
public Buyer() {}
public Buyer(int id, string name)
{
ID = id;
BuyerName = name;
}
public Buyer(string name)
{
ID = 0;
BuyerName = name;
}
}
xaml.cs
public partial class BuyerInfoControl : UserControl
{
Buyer b;
public BuyerInfoControl()
{
InitializeComponent();
b = new Buyer(txtBuyerName.Text);
this.DataContext = b;
}
}
when a value of "John Doe" is typed in the TextBox and the button is clicked, the buyer's name is null. I usually work in swfit, object-c and MVC. Trying to figure how to play with MVVM and WPF. I have a feeling I'm doing some wrong here.
Here's the design

b = new Buyer(txtBuyerName.Text); only gets the last reference to the state of Text; meaning that it is a snapshot.
To achieve proper binding, it has to occur on the main page where the custom control resides and like the TextBox it will need to bind to the source string. To do that one must provide a Dependency Property on the custom control.
For example, if a dependency property named MyText is added to the control bind like this:
<InvoiceControl MyText="{Binding Path=BuyerName}"/>
<TextBox x:Name="txtBuyerName" Text="{Binding Path=BuyerName, Mode=TwoWay}"
TextWrapping="NoWrap"/>
Since InvoiceControl is a user control, the user control on the main page has to also be bound to the originating BuyerName (as shown) and to do what you want it has to happen via a dependency property put on InvoiceControl.
Wire up a dependency property on InvoiceControl as such:
#region public string MyText
/// <summary>
/// This the dependency property for the control.
/// </summary>
public string MyText
{
get { return GetValue(MyTextProperty) as string; }
set { SetValue(MyTextProperty, value); }
}
/// <summary>
/// Identifies the MyText dependency property.
/// </summary>
public static readonly DependencyProperty MyTextProperty =
DependencyProperty.Register(
"MyText",
typeof(string),
typeof(InvoiceControl),
new PropertyMetadata(string.Empty));
#endregion public string MyText
then load like this
MessageBox.Show(MyText);
See Dependancy Property Overview
Also there may be an issue where you are trying to do the button click, right after typing into the control and the proper change event doesn't fire.
In the TextBox put in the binding UpdateSourceTrigger=PropertyChanged on the so that every text change sends a notification message. That way if one types in and focus moves to the button, the two way binding notification will fire.
Note if you work with custom controls this link has Visual Studio snippets which put in fillable templates for dependency properties in the editor. Ignore the title with Siverlight and opy the snippets to C:\Users\{You}\Documents\Visual Studio 20{XX}\Code Snippets\Visual C#\My Code Snippets, for they will work with all versions of visual studio:
Helpful Silverlight Snippets - Jeff Wilcox

Related

Value Update notifications between ViewModels

I have a Tab Control, with an "Exams" tab and a "Templates" tab. I want to share information between the two tabs.
My background is mostly in web with React and Redux, so my instinct is to have the shared information (of model type Exam) belong to the MainWindow, probably as a window resource.
My tech lead, who is much more experienced than me -- in all things, but also in C# though he's also new to WPF), assures me that this is not the way to do it in this setting, that the tabs' ViewModels should be sharing/passing the information.
So I've set up my basic UI with a text box in the Exams tab and a label to display the contents of the text box in the Templates tab.
<Page x:Class="Gui.Tabs.ExamsTab.ExamsHome" Title="ExamsTab">
<Grid VerticalAlignment="Center">
<StackPanel>
<Label Content="EXAMS TAB" />
<TextBox Text="{Binding ExamString, UpdateSourceTrigger=PropertyChanged}"/>
<Label Content="{Binding ExamString}" />
</StackPanel>
</Grid>
</Page>
--------
<Page x:Class="Gui.Tabs.TemplatesTab.TemplatesHome" Title="TemplatesHome">
<Grid VerticalAlignment="Center">
<StackPanel>
<Label Content="TEMPLATES TAB"/>
<Label Content="Text from Exams tab:"/>
<Label BorderBrush="Red" BorderThickness="1" Content="{Binding StringFromExamsTab}"/>
</StackPanel>
</Grid>
</Page>
And I've wired up the ViewModels best I can: (the code-behind and the viewmodels are in the same file for now)
namespace Gui.Tabs.ExamsTab {
public partial class ExamsHome : Page {
public ExamsHome() {
InitializeComponent();
DataContext = ViewModel;
}
public static readonly ExamsTabViewModel ViewModel = new ExamsTabViewModel();
}
public class ExamsTabViewModel :INotifyPropertyChanged {
private string _examString = "Default exam string";
public string ExamString {
get => _examString;
set {
_examString = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "") {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
------
namespace Gui.Tabs.TemplatesTab {
public partial class TemplatesHome : Page {
public TemplatesHome() {
InitializeComponent();
DataContext = viewModel;
}
public static readonly TemplatesTabViewModel viewModel = new TemplatesTabViewModel();
}
public class TemplatesTabViewModel {
public string StringFromExamsTab {
// needs to be notified of value change!
get => ExamsHome.ViewModel.ExamString;
}
}
}
In the Exams tab, the text-box and its corresponding label are synced up.
And, in the Templates tab, the red box says "Default exam string", but it doesn't change with the value in the text-box.
I've read that:
The XAML binding engine listens for [the PropertyChangedEvent] for each bound property on classes that implement the INotifyPropertyChanged interface
Which implies to me that as long as INotifyPropertyChanged is implemented in the Exams VM, the bindings in the Templates tab should be notified.
How can I make this work? Open to the possibility that I'm doing it entirely (or mostly) wrong.

WPF DependencyProperty OnPropertyChanged returns default value as NewValue if using DataTemplate on UserControl

I have an application in which I set the content of a contentpresenter, dependent on the datatype by a datatemplate (see MainWindow). The Datatemplate is a usercontrol, which is actually datatype specific. (The small example below is only for demonstration, but in my "real" application the user shall be able to switch between different data.)
The usercontrol (UserControl1) has a DependencyProperty which I assign a value (in my application this is actually a binding to a VM, just set it to a string in example for simplicity).
Setting the value is still working fine. However In my UserControl I need to react to changes of the DependencyProperty to change the view of my UserControl (or later on CustomControl). So I implemented a OnPropertyChangend method.
When application starts OnPropertyChanged works as I expect it and I get the "correct" newvalue of my DependencyProperty. However, if I change my VM (i.e. my datatemplate changes) during runtime by clicking on a button, OnPropertyChanged returns the DependencyProperty's defaultvalue.
In my small example application, I can see that the value is set correctly, as the Textblock content changes to the correct value.
It only seems that OnPropertyChanged gets fired before my DependencyProperty's value gets the new value. So, it's not possible for me to react on the new value.
It is not really clear why this happens. Seems to have something to do with the order in which WPF resolves internal stuff?
Does anyone have a clue, how I can fix this behavior and get access to the current/last value when changing my VM and don't miss an update? As stated out before, I need to react on that value.
Maybe I am doing something totally stupid here. Is the approach I decided to use here a bad one? Are DataTemplates the wrong approach to switch between two pairs? What would be a better approach then? However, I guess it won't be possible to avoid the DependencyProperty and the UserControl in my application.
MainWindow.xaml
<!--MainWindow.xaml -->
<Grid>
<StackPanel>
<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
<ContentPresenter Content="{Binding ActiveVM}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type local:VM1}">
<local:UserControl1 MyProperty="Test1"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:VM2}">
<local:UserControl1 MyProperty="Test2"/>
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
</StackPanel>
</Grid>
MainWindow.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
vmParent = new VMParent();
DataContext = vmParent;
var vm1 = new VM1();
var vm2 = new VM2();
}
VMParent vmParent;
private void Button_Click(object sender, RoutedEventArgs e)
{
vmParent.ChangeActiveVM();
}
}
UserControl1.xaml
<!--UserControl1.xaml -->
<TextBlock Text="{Binding MyProperty, RelativeSource={RelativeSource AncestorType={x:Type local:UserControl1}}}"/>
UserControl1.cs
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public string MyProperty
{
get { return (string)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(string), typeof(UserControl1), new PropertyMetadata("DefaultString", OnMyPropertyChangend));
private static void OnMyPropertyChangend(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == "DefaultString")
{
;
//xxxxxx
//unexpectedly i get stuck here
//Would expect/need NewValue to be Text1/Text2 to react to it
//xxxxxx
}
}
}
VMParent
class VMParent : INotifyPropertyChanged
{
public VMParent()
{
vm1 = new VM1();
vm2 = new VM2();
ActiveVM = vm1;
}
public event PropertyChangedEventHandler PropertyChanged;
VM1 vm1;
VM2 vm2;
public object ActiveVM
{
get => m_activeVM;
set { m_activeVM = value; OnPropertyChanged("ActiveVM"); }
}
private object m_activeVM;
protected internal void OnPropertyChanged(string propertyname)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
public void ChangeActiveVM()
{
if (ActiveVM is VM1)
ActiveVM = vm2;
else
ActiveVM = vm1;
}
}
VMs are only used to apply Datatemplate
class VM1
{
}
class VM2
{
}

Binding model with multiple properties in UserControl using one DependencyProperty [duplicate]

This question already has answers here:
Issue with DependencyProperty binding
(3 answers)
Closed 4 years ago.
I would like to be able to bind complex model (many properties) to UserControl through DependencyProperty, and if model would be edited in UserControl I would like to see this edited information inside my binded model.
Example application: Model, UserControl (xaml + cs), MainWindow (xaml + cs). I have no ViewModel to simplify idea.
Model:
public class MyModel : INotifyPropertyChanged
{
private string _surname;
private string _name;
public string Name
{
get => _name;
set
{
_name = value;
OnPropertyChanged();
}
}
public string Surname
{
get => _surname;
set
{
_surname = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
MyModelEditor.xaml (inside Grid):
<DockPanel>
<TextBox Text="{Binding MyModel.Name}"/>
<TextBox Text="{Binding MyModel.Surname}"/>
</DockPanel>
Also contains this line in UserControl root element:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
MyModelEditor.xaml.cs:
public partial class MyModelEditor : UserControl
{
public MyModel MyModel
{
get => (MyModel)GetValue(MyModelProperty);
set => SetValue(MyModelProperty, value);
}
public static readonly DependencyProperty MyModelProperty =
DependencyProperty.Register("MyModel", typeof(MyModel), typeof(MyModelEditor), new FrameworkPropertyMetadata(null));
public MyModelEditor()
{
InitializeComponent();
}
}
MainWindow.xaml (inside Grid):
<DockPanel>
<Button DockPanel.Dock="Bottom" Content="Press Me!" Click="ButtonBase_OnClick"/>
<controls:MyModelEditor MyModel="{Binding MyModel}"/>
</DockPanel>
MainWindow.xaml.cs:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private MyModel _myModel;
public MyModel MyModel
{
get => _myModel;
set
{
_myModel = value;
OnPropertyChanged();
}
}
public MainWindow()
{
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
MessageBox.Show(MyModel?.Name);
}
}
My test scenario: type text in textbox, press button.
Current behavior: Message after pressing button is empty.
Expected behavior: Message after pressing button is same like in textbox.
I wold not like to bind to all properties separately, because in future I will have much more then two properties.
Why current approach does not work?
How can I achieve my goal?
You are apparently not using the UserControl instance as Binding source in your UserControl's XAML. One way to do this would be to set the Binding's RelativeSource:
<TextBox Text="{Binding MyModel.Name,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
However, you don't need a new dependency property at all for this purpose. Just bind the UserControl's DataContext to a MyModel instance, like
<controls:MyModelEditor DataContext="{Binding MyModel}"/>
The Bindings in the UserControl's XAML would automatically work with the MyModel object, like this:
<DockPanel>
<TextBox Text="{Binding Name}"/>
<TextBox Text="{Binding Surname}"/>
</DockPanel>
For both of your TextBox controls, you should define their Binding with a TwoWay mode (ms docs on binding modes). Which, basically, would assure that the data flow is working in both direction (i.e. from the view model into the view and the other way around):
<DockPanel>
<TextBox Text="{Binding MyModel.Name, Mode=TwoWay}"/>
<TextBox Text="{Binding MyModel.Surname, Mode=TwoWay}"/>
</DockPanel>
As a good practice, you should always explicitly define what is the mode of the the Binding (NOTE: by default it's OneWay TwoWay - how to know which is the default?).
Another tip would be to go ahead and use MvvmHelpers nuget (github project), which could spare you the time of implementing INotifyPropertyChanged. Besides, you shouldn't re-invent the wheel
EDIT: Fixes are in your GitHub repo
Two things to note here
You have not instantiated your ViewModel (i.e. MyModel), so it was always null
You don't need to create DependencyPropery every time you want to pass some information to your UserControl. You could simply bind the DataContext itself

WPF Binding ViewModel property to Attached Property

My goal is to create add Text property to RichTextBox. I created Attached Property and set binding to ViewModel's property. Unfortunately changing text in RichTextBox doesn't update underlying property.
Here is my code:
View.cs:
public partial class KnuthMorrisPrattView : UserControl
{
public KnuthMorrisPrattView()
{
InitializeComponent();
}
public static string GetText(DependencyObject obj)
{
return (string)obj.GetValue(TextProperty);
}
public static void SetText(DependencyObject obj, string value)
{
obj.SetValue(TextProperty, value);
}
public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached
(
"Text",
typeof(string),
typeof(KnuthMorrisPrattView),
new FrameworkPropertyMetadata()
{
BindsTwoWayByDefault = true,
PropertyChangedCallback = PropertyChangedCallback,
CoerceValueCallback = CoerceValueCallback,
DefaultUpdateSourceTrigger = UpdateSourceTrigger.LostFocus
}
);
private static object CoerceValueCallback(DependencyObject dependencyObject, object baseValue)
{
throw new NotImplementedException();
}
private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
throw new NotImplementedException();
}
}
View.xaml:
<UserControl x:Class="Launcher.Views.KnuthMorrisPrattView"
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:views="clr-namespace:Launcher.Views"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="500"
DataContext="{Binding KnuthMorrisPrattViewModel, Source={StaticResource MainViewModel}}">
<Grid Margin="15">
<Grid.RowDefinitions>
<RowDefinition Height="7*"/>
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0">
<Label Content="Text" DockPanel.Dock="Top"></Label>
<RichTextBox x:Name="TextBox" views:KnuthMorrisPrattView.Text="{Binding TextToSearchArg}"/>
</DockPanel>
<DockPanel Grid.Row="1">
<Label Content="Pattern" DockPanel.Dock="Top"></Label>
<TextBox Text="{Binding PatternArg}"/>
</DockPanel>
</Grid>
ViewModel.cs:
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using GalaSoft.MvvmLight.CommandWpf;
using Launcher.Runners.KnuthMorrisPratt;
namespace Launcher.ViewModels
{
public class KnuthMorrisPrattViewModel : ViewModelBase
{
private string _textToSearchArg;
private string _patternArg;
public string TextToSearchArg
{
get { return _textToSearchArg; }
set
{
_textToSearchArg = value;
RaisePropertyChanged();
}
}
public string PatternArg
{
get { return _patternArg; }
set
{
_patternArg = value;
RaisePropertyChanged();
}
}
public KnuthMorrisPrattViewModel()
{
}
}
}
I know that Callback throws and exception but my goal here is to just see under the debugger that this callback is invoked. Then I add correct implementation.
EDIT:
I think I missed important note about my issue. When I update TextToSearchArg property from code everything works correctly. The only problem is that when I set some text in RichTextBox underlying property is not updated.
What am I missing? Thanks a lot in advance.
Nothing in your code shows that the Attached property is bound to the RichTextBox events, hence it won't ever be called if the content/text in RichTextBox changes.
You'd need to subscribe to the RichTextBox.TextChanged event.
public partial class KnuthMorrisPrattView : UserControl
{
public KnuthMorrisPrattView()
{
InitializeComponent();
this.TextBox.TextChanged += OnTextChanged;
}
...
public void OnTextChanged(object sender, TextChangedEventArgs e)
{
// Get the text from the event and set your Text Property
string text = ...;
SetText(this, text);
}
}
Edit:
In case you want to listen to another control's Dependency/Attached Property changes, use
DependencyPropertyDescriptor.FromProperty(ControlClassName.DesiredPropertyProperty, typeof(ControlClassName)).AddValueChanged(dependencyObject, OnDesiredPropertyChanged);
Where...
ControlClassName is the class containing the Dependency Property (i.e. RichTextBox in your case or the class where the Dependency/Attached Property is defined
'DesiredPropertyPropertyis the name of your property (i.e.TextProperty`
dependencyObject is the instance of object where the DesiredPropertyProperty is set on
OnDesiredPropertyChanged method to call when the property value changes
On a side note:
You should have Code-Behind in the view. There is no requirement that Dependency Properties or Attached Properties have to be defined inside the same class as the are meant for.
Code behind should only be used, if it's an reusable User Control but the naming of your class suggest it's not a User Control (even though it derives form User Control) but a View.
A view is application specific and can't be reused outside that specific app and is only meant to display a certain content. If you make a "LoginControl" then it it can be made to be reusable in other. A "LoginView" on other side doesn't suggest re-usability.
Maybe
Mode=TwoWay, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged
on the binding missing?

Metro: Why is binding from XAML to a property defined in code-behind not working?

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.

Categories