I have TextBox in XAML that appears to be bound correctly and the UI will correctly update when the datasource is changed. I'm attempting to do this in the "proper WPF way" as recommended by several articles. The problem I'm having is that the UI thread is continuing to do work and the UI will not update immediately despite executing the datasource update on a separate thread.
//XAML
<Window x:Class="WPFDataBindingTest.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:WPFDataBindingTest"
mc:Ignorable="d"
Title="MainWindow" Height="480" Width="759">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="900*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="380"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<TextBox Name="tbFileTransferLog" Grid.Row="0" Grid.Column="0" FontSize="15" Width="740" Height="360" HorizontalAlignment="Left" TextWrapping="Wrap" Margin="5" AcceptsReturn="True" VerticalScrollBarVisibility="Visible"/>
</Grid>
<Button Grid.Column="0" Grid.Row="1" Width="200" Height="40" Click="UpdateTextboxButton_Click">Update Textbox</Button>
</Grid>
</Window>
//C#
public class TextBlockUpdate : INotifyPropertyChanged
{
private string _tbFileTransferLogText;
// Declare the event
public string tbFileTransferLogText
{
get { return _tbFileTransferLogText; }
set
{
_tbFileTransferLogText = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged();
}
}
// Create the OnPropertyChanged method to raise the event
// The calling member's name will be used as the parameter.
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
public MainWindow()
{
InitializeComponent();
}
public void UpdateTextboxButton_Click(object sender, RoutedEventArgs e)
{
TextBlockUpdate textBlockUpdate = new TextBlockUpdate();
Binding nameBindingObject = new Binding("tbFileTransferLogText");
// Configure the binding
nameBindingObject.Mode = BindingMode.OneWay;
nameBindingObject.Source = textBlockUpdate;
//nameBindingObject.Converter = NameConverter.Instance;
nameBindingObject.ConverterCulture = new CultureInfo("en-US");
nameBindingObject.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
// Set the binding to a target object. The TextBlock.Name property on the NameBlock UI element
BindingOperations.SetBinding(tbFileTransferLog, TextBox.TextProperty, nameBindingObject);
//tbFileTransferLog.Dispatcher.BeginInvoke(new Action(() => textBlockUpdate.tbFileTransferLogText = "text is updated" + Environment.NewLine));
//Task.Factory.StartNew(() => { textBlockUpdate.tbFileTransferLogText = "text is updated"; });
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
/* run your code here */
textBlockUpdate.tbFileTransferLogText = "text is updated";
}).Start();
Thread.Sleep(10000);
}
What I noticed (using debug mode) is that both the setter and OnPropertyChanged() are executed immediately when the button is clicked, but the UI is not updated until later when Sleep() completes.
What am I missing?
Thanks.