Reputation: 2921
OK... I'm a VB.NET WinForms guy trying to understand WPF and all of its awesomeness. I'm writing a basic app as a learning experience, and have been reading lots of information and watching tutorial videos, but I just can't get off the ground with simple DataBinding, and I know I'm missing some basic concept. As much as I'd love it, I haven't had that "Aha!" moment when reviewing source code yet.
So... In my Window class I defined a custom string Property. When I go into Blend, I try to databind my TextBox's Text to this property, but my Property doesn't show up in Blend as something that available for Binding to.
Can someone tell me what I need to add to my code/XAML below... and most importantly why?
My XAML:
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<TextBox Text="How do I Bind my SomeText property here?"></TextBox>
</Grid>
</Window>
My Window Code:
Class Window1
Private _sometext As String = "Hello World"
Public Property SomeText() As String
Get
Return _sometext
End Get
Set(ByVal value As String)
_sometext = value
End Set
End Property
End Class
Upvotes: 1
Views: 661
Reputation: 7427
Data binding with a CLR property requires an extra step. You have to implement INotifyPropertyChanged and fire the PropertyChanged event whenever that CLR property changes. This won't make it appear in Blend, but you can bind to the property using Text="{Binding SomeText}" and setting the window's DataContext to your object.
There is an alternative. Instead of using .NET data binding, consider Update Controls .NET. It's an open source project that replaces data binding and does not require INotifyPropertyChanged. The great thing about Update Controls is that it can see through intermediate business logic. With INotifyPropertyChanged you have to catch and re-fire events.
Upvotes: 0
Reputation: 14262
For data binding it is helpful to think about several things:
In your sample code:
The Binding markup extension goes on the Target property of the Target object.
Here is a picture which illustrates the above:
Check out the following code (one way to solve this problem):
<Window
x:Class="WpfApplication2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="theWindow"
Title="Window1"
Height="300"
Width="300"
>
<Grid>
<StackPanel>
<TextBox Text="{Binding ElementName=theWindow, Path=SomeText}"/>
<Button
Width="100"
Height="25"
Content="Change Text"
Click="Button_Click"
/>
</StackPanel>
</Grid>
</Window>
In the Binding markup extension, I have defined the source using ElementName ... which allows you to use another element in your visual tree as the source. In doing so, I also had to give the window a name with the x:Name attribute.
There are several ways to define a source with Binding (i.e. Source, ElementName, DataContext) ... ElementName is just one way.
One thing to note is that the Source property doesn't have to be a Dependency Property, but if it isn't, then the Target property won't update ... without some special help. Check out the following piece of code (my apologies it is C#, that was quicker for me). In it you will see me implement INotifyPropertyChanged. This allows a source object to say that something has changed ... and the data binding is smart enough to watch for it. Thus, if you click the button (from the example code here), it will update the TextBox. Without implementing this interface (and if you click the button), the TextBox would not update.
I hope that helps.
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window, INotifyPropertyChanged
{
public Window1()
{
InitializeComponent();
}
private string _someText = "Hello World!";
public string SomeText
{
get { return _someText; }
set
{
_someText = value;
OnNotifyPropertyChanged("SomeText");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnNotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
private void Button_Click(object sender, RoutedEventArgs e)
{
this.SomeText = "Goodbye World!";
}
}
Upvotes: 5
Reputation: 1900
WPF DataBinding is a very powerful feature. I suggest to read some already existing articles on the web, such as
Very helpful to me was also Beatrix Costa's blog on Data Binding.
Upvotes: 1
Reputation: 33280
Here's how you need to change your XAML (the code is fine).
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<TextBox Text="{Binding SomeText}">
</TextBox>
</Grid>
</Window>
To understand Bindings in WPF, you need to understand the DataContext. Every element has a DataContext property, and any object you put in that property becomes the data source of any bindings which do not have an explicit data source specified. The value of the DataContext is inherited from a parent object (so in this case the TextBox inherits the Grid's DataContext, which inherits the Window's DataContext). Since you want to refer to a property of the window, you need to set the DataContext to point to the Window instance, which is what I do in the DataContext attribute of the Window.
You can also change the data source for individual bindings by using the Source= or RelativeSource= syntax in the {Binding } element.
Upvotes: 6