I'm a C# newbie who's having problems understanding why his first attempt at understanding XAML bindings isn't working. I'm following Microsoft's Data Binding Overview.
I have a single TextBox which will eventually serve as a status window. For now I just want to be able to write arbitrary text strings into it. I also have an instance of the command pattern that I'm testing. My command involves adding a random number to an accumulator and printing out the result to the status view.
Here's my XAML for the main application window:
<Window x:Class="Experiment.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:Experiment"
Title="Test" Height="500" Width="700" Name="Test" Closing="Test_Closing" DataContext="{Binding ElementName=statusText}" xmlns:my="clr-namespace:Experiment">
<Window.Resources>
<c:StatusViewText x:Key="statusViewText" />
</Window.Resources>
<DockPanel HorizontalAlignment="Stretch" Margin="0,0,0,0" Width="Auto">
<!-- Elements deleted for brevity. -->
<TextBox Margin="5,5,5,5" Name="statusText" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" AcceptsReturn="True" AcceptsTab="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" FontFamily="Courier New" FontSize="12"
Text="{Binding Source={StaticResource statusViewText}, Path=statusTextString, Mode=OneWay}"/>
</DockPanel>
</Window>
And the class representing my data:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Experiment {
public class StatusViewText {
public StringBuilder statusText { get; set; }
public String statusTextString { get; set; }
public StatusViewText() {
statusText = new StringBuilder();
}
public void Append(string s) {
if (s != null) {
statusText.Append(s);
}
statusTextString = statusText.ToString();
}
public void AppendLine(string s) {
if (s != null) {
statusText.AppendLine(s);
}
statusTextString = statusText.ToString();
}
}
}
Eventually I'll use a proper converter here from StringBuilder, but I wanted to get the principle down before exploring that complexity.
If my understanding were correct (and obviously it isn't), this all SHOULD work. The binding target is the TextBox, target property is the Text property. The binding source is the StatusViewText class's statusTextString property. Yet when I run the command (and debug and see StatusViewText.statusTextString being updated), the TextBox doesn't update.
I thought that I may need to explicitly add the binding myself, so I tried adding this after InitializeComponent() in the main window constructor:
statusViewText = new StatusViewText();
Binding statusViewTextBinding = new Binding("statusTextString");
statusViewTextBinding.Source = statusViewText;
statusText.SetBinding(TextBlock.TextProperty, statusViewTextBinding);
but that didn't work either.
Do I need to fire PropertyChanged events? I thought the entire point of the binding framework is that events are fired and consumed behind the scenes, automagically; but maybe I'm wrong there too.
No obvious errors are coming up in the Output window which leads me to believe that my binding syntax is correct; I'm just missing something else.
Halp!
EDIT 13:14 EDT Thanks mben:
Ok, I did that. Added the following:
public class StatusViewText : INotifyPropertyChanged {
public void Append(string s) {
if (s != null) {
statusText.Append(s);
}
statusTextString = statusText.ToString();
NotifyPropertyChanged("statusTextString");
}
public void AppendLine(string s) {
if (s != null) {
statusText.AppendLine(s);
}
statusTextString = statusText.ToString();
NotifyPropertyChanged("statusTextString");
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info) {
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
I debugged to verify that it was going through this code path, and it is. But still no luck. Any other thoughts?