9

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?

0

2 Answers 2

25

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 the TextBox is. DataContext is essentially the "thing" your TextBox 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's DataContext from the Grid element, which in turn inherits it's DataContext from the Window element. Seeing that DataContext is not set in your Window the default value of the DataContext property will be applied, which is null. The DataContext is also not set in any of the child elements of your window, which, via inheritance, will set the DataContext of all children of that window to null.

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 to DataContext.str which resolved by WPF is null.str.

OK, cool. Now, how do we set the DataContext of your TextBox.Text binding to the Code Behind for the window so we can get at that str property? There are several ways to do this, but for our purposes we'll focus on setting it explicitly in the binding of the TextBox.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 have Source, RelativeSource, and ElementName. We're only going to focus on ElementName here, but the others are essential to research and understand.

So, let's name our Window element so we can access it through the ElementName property.

<Window x:Class="WpfApplication1.MainWindow" x:Name="_window" ... 

Now we can set the ElementName property on the TextBox.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 your str value reflected in the TextBox. This is because it's value is set after the InitializeComponent method in the window's constructor. This function is where bindings are resolved for the first time. If you were to set the value of str before calling InitializeComponent, you would see the value reflected in the TextBox.

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 your str property.

public static readonly DependencyProperty StrProperty = DependencyProperty.Register("Str", typeof(string), typeof(MainWindow), new FrameworkPropertyMetadata(FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public string Str { get{return (string)GetValue(StrProperty);} set{SetValue(StrProperty,value);} } 

Now you'll be able to set the value like such and have it reflect through the binding to your TextBox.

public MainWindow() { InitializeComponent(); Str = "OK"; } 

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, and DependencyProperty as these are the core of WPF. Good luck!

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for taking your time to explain it to me. So does that mean if I set a "DataContext" to the` Binding Source` to make it work as an alternative? In your example, can I set {Binding Source=_window ...} and make it work?
You're very welcome. Thanks for the opportunity to help! As for your question, the answer is no. The ElementName property is the only one that can be used with the x:Name attribute of your Window. Source is used for static and dynamic resources, which is a little more advanced.
It may help to envision the Source as being only one of the three ways to explicitly resolve a binding object or "Source". I know this is confusing. You can use Source, RelativeSource, or ElementName, which are all mutually exclusive. You can also use none of these and leave the "Source" area blank, which resolves to DataContext. Notice the difference between Source and "Source". Source is an actual property of a binding, "Source" is semantics for referring to the underlying source object of the binding.
5

The problem is that, you dont bind to codebehind of Window, but to DataContext.

Try this:

public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new DC(); } public class DC { public string str { get; set; } public DC() { str = "OK"; } } } 

Normally, you would have two different files, but for test, you can do it in one file. After that, your DC (DataContext) should implement INotifyPropertyChanged interface.

Try to find some article about MVVM like this http://www.codeproject.com/Articles/165368/WPF-MVVM-Quick-Start-Tutorial

6 Comments

Or you can set your DataContext to this, but that is really bad idea. You should separate your ViewModel and your View.
So, setting the DataContext solves the issue. Is there anyway that I can make it work without having to instantiate an object, just use the string property directly? Is the answer for this question setting DataContext to this?
You can bind to the code behind of the window, there's nothing wrong with that: public MainWindow { InitializeComponent(); **DataContext = this;** }
OK, it does work with setting the DataContext to this. Thanks @Jakub Čermoch , @slugster! I also take your consideration to separate the Model and View. This is just a test for me to understand the concept and the code.
But this was just for show you, how to do it easiest way. If you are goingt to do bigger project in WPF, use MVVM is almost necessary. Try to find some articles about it. Good is use Prism for implementation of MVVM with WPF
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.