I have a WPF project in which I have 4 TextBlock
. What I want is to change the Text
of each TextBlock
via Binding
.
So far I have my XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock x:Name="First" Text="{Binding FirstString}" Grid.Row="0"/>
<TextBlock x:Name="Second" Text="{Binding SecondString}" Grid.Row="1"/>
<TextBlock x:Name="Third" Text="{Binding ThirdString}" Grid.Row="2"/>
<TextBlock x:Name="Fourth" Text="{Binding FourthString}" Grid.Row="3"/>
</Grid>
And in my code I have:
public partial class MainWindow : Window
{
public string FirstString { get; set; }
public string SecondString { get; set; }
public string ThirdString { get; set; }
public string FourthString { get; set; }
public MainWindow()
{
InitializeComponent();
FirstString = "First";
SecondString = "Second";
ThirdString= "Third";
FourthString= "Fourth";
}
}
But the Binding
doesn't work at all. Am I doing something wrong?
EDIT: After following Chris Mantle's suggestion in the comments to look at the debug output (I had to enable Warnings for the Binding), I get the following error:
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=FirstString; DataItem=null; target element is 'TextBlock' (Name='First'); target property is 'Text' (type 'String')
There are a few things that are incorrect. The Binding
markup will look at the object in the DataContext
property of the control. This property inherits the DataContext
from the declaring parent unless otherwise specified. Out of the box, this is null
for a Window
control.
There are two options for this problem. You can either set the DataContext
explicitely in the code-behind or the XAML
// In XAML
<Window DataContext={Binding RelativeSource={RelativeSource Self}}>
or
// In the code-behind
DataContext = this;
Another problem is that the binding is applied at initialization. Initially, your properties are empty. After the InitializeComponent
phase, the controls will "bind" to the properties (which are empty). When you set your properties afterward, the controls have no way to know it has changed. There are two mechanism to allow this. On the control level, you can make these properties as DependencyProperty
or implement the INotifyPropertyChanged
interface and raise the changes. If you want to go the INPC route, you can implement your properties and Window as such:
public partial class MainWindow : INotifyPropertyChanged
{
private string firstString;
private string secondString;
private string thirdString;
private string fourthString;
public string FirstString
{
get { return firstString; }
set
{
firstString = value;
RaisePropertyChanged("FirstString");
}
}
public string SecondString
{
get { return secondString; }
set
{
secondString = value;
RaisePropertyChanged("SecondString");
}
}
public string ThirdString
{
get { return thirdString; }
set
{
thirdString = value;
RaisePropertyChanged("ThirdString");
}
}
public string FourthString
{
get { return fourthString; }
set
{
fourthString = value;
RaisePropertyChanged("FourthString");
}
}
public MainWindow()
{
DataContext = this;
InitializeComponent();
FirstString = "First";
SecondString = "Second";
ThirdString = "Third";
FourthString = "Fourth";
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string propertyName)
{
var handlers = PropertyChanged;
handlers(this, new PropertyChangedEventArgs(propertyName));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With