I am very sorry that this question is very basic. I just learned WPF and I failed to make simple two way binding to textbox.text to string property.
XAML Code:
<Window x:Class="WpfApplication1.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:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="StuInfo">
<TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="10,26,0,0" TextWrapping="Wrap" Text="{Binding Path=str,Mode=TwoWay}" VerticalAlignment="Top" Width="120"/>
<Button x:Name="button" Content="Check" HorizontalAlignment="Left" Margin="10,67,0,0" VerticalAlignment="Top" Width="75" Click="button_Click"/>
</Grid>
C# Code
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
str = "OK";
}
public string str { get; set; }
private void button_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine(str);
}
}
First, the textbox does not show "OK", but it is blank. Then, I typed a different text into the textbox, for ex:"blablabla" without the quotes. Then I click the button to check if my str property has been updated. Apparently, str still contains "OK".
What did I do wrong here? What did I miss to make the binding work?
Best Answer
As a newcomer to WPF, all this Binding and DataContext jazz can be quite confusing. Let's start with your binding expression first...
<TextBox Text="{Binding Path=str, Mode=TwoWay}"/>
What this is saying is that you want to bind your Text property to whatever the
DataContext
of theTextBox
is.DataContext
is essentially the "thing" yourTextBox
is getting it's data from. Now here's the rub.DataContext
is inherited from the element "above" it in the visual tree if not explicitly set. In your code,TextBox
inherits it'sDataContext
from theGrid
element, which in turn inherits it'sDataContext
from theWindow
element. Seeing thatDataContext
is not set in yourWindow
the default value of theDataContext
property will be applied, which isnull
. TheDataContext
is also not set in any of the child elements of your window, which, via inheritance, will set theDataContext
of all children of that window tonull
.It is important to note that you've left out the
Source
property in your binding expression.<TextBox Text="{Binding Source=left_out, Path=str, Mode=TwoWay}"/>
When this property is left out, the binding's source is implied to be the elements
DataContext
, which in this case is null, for the reasons mentioned above. Basically, what your expression is saying here is that you want to bind your text property toDataContext.str
which resolved by WPF isnull.str
.OK, cool. Now, how do we set the
DataContext
of yourTextBox.Text
binding to the Code Behind for the window so we can get at thatstr
property? There are several ways to do this, but for our purposes we'll focus on setting it explicitly in the binding of theTextBox.Text
property. Now, there are three different "source" type properties of bindings. "Source" being where we want our control/element's binding to get it's data from. We haveSource
,RelativeSource
, andElementName
. We're only going to focus onElementName
here, but the others are essential to research and understand.So, let's name our
Window
element so we can access it through theElementName
property.Now we can set the
ElementName
property on theTextBox.Text
binding to refer to the window.<TextBox Text="{Binding ElementName=_window, Path=str, Mode=TwoWay}"/>
This means the binding will look for the
_window.str
property when trying to resolve it's binding. At this point, you still probably won't see yourstr
value reflected in theTextBox
. This is because it's value is set after theInitializeComponent
method in the window's constructor. This function is where bindings are resolved for the first time. If you were to set the value ofstr
before callingInitializeComponent
, you would see the value reflected in theTextBox
.This brings us to Dependency Properties. For now, just know that Dependency Properties have built in change notification, which your binding needs so it "knows" when the binding has changed and when to resolve the binding value again. Yes, you could use
INotifyPropertyChanged
in your code behind, but there are good arguments for using DependencyProperties in this case, which will only confuse the issue at this point. But, it is another one of those things that is essential to understand.Here is the code for a
DependencyProperty
for yourstr
property.Now you'll be able to set the value like such and have it reflect through the binding to your
TextBox
.At this point, all should be well. I hope this helps out. It took me a while get the hang of WPF. My suggestion would be to read as much as you can on
DataContext
,Binding
, andDependencyProperty
as these are the core of WPF. Good luck!