I have delved into the magic and mystery of WPF and Binding. It was going OK then I hit a brick wall and need to ask those much cleverer than me for help please.
I cut this back to a simple app removing all the other items in my code. The UI has a text box and a label. When the text in the textbox changes then I want to update the label. Somewhere I am missing a link and I guess it is the binding as I never seem to get into the set. Here is the code
Mainwindow.xaml.cs
using System.ComponentModel;
using System.Windows;
namespace Databinding3
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
private string myBindedVal = "....";
public MainWindow()
{
InitializeComponent();
}
//Create properties for our variable _myBindedVal
public string MyBindedVal
{
get => myBindedVal;
set
{
NotifyPropertyChanged(nameof(MyBindedVal));
myBindedVal = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (propertyName != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Mainwindow.xml
<Window x:Class="Databinding3.MainWindow"
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"
xmlns:local="clr-namespace:Databinding3"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBox x:Name="txtbx_name" Text="Textbox" HorizontalAlignment="Center" Height="57" TextWrapping="Wrap" VerticalAlignment="Center" Width="594"/>
<Label Content="{Binding MyBindedVal, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" HorizontalAlignment="Center" Height="44" Grid.Row="1" VerticalAlignment="Center" Width="594"/>
</Grid>
</Window>
Thanks for your help
CodePudding user response:
You did not bind the Text property of the TextBox. It should look like shown below, where the UpdateSourceTrigger ensures that the source property is updated immediately when you type into the TextBox.
<TextBox Text="{Binding MyBoundVal, UpdateSourceTrigger=PropertyChanged}" .../>
The above Binding does not explicitly specify a source object, and therefore uses the Window's DataContext as source. Set the DataContext like this:
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
The Label Binding would then just be
<Label Content="{Binding MyBoundVal}" .../>
Be aware that you would typically use a TextBlock, not a Label, to show text:
<TextBlock Text="{Binding MyBoundVal}" .../>
The execution order in the property setter is also important. Assign the backing field value before firing the PropertyChanged event.
public string MyBoundVal
{
get => myBoundVal;
set
{
myBoundVal = value;
NotifyPropertyChanged(nameof(MyBoundVal));
}
}
Finally, the NotifyPropertyChanged method should look like shown below. Testing the propertyName
argument is pointless, but you should test the PropertyChanged
event for null, usually by using the null-propagation operator ?.
:
private void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}