Search code examples
c#wpfdata-bindingmessagebox

WPF C# Databinding - MessageBox.Show


Let me start off by stating I have read so many threads my head hurts, I've tried most of them and still have not had success.

My issues is pretty simple. I have some status I want to update a control with, I have a TextBox bound to an object class.

When I step through the code the textbox.Text is being updated just never rendered. What I noticed was if I use other windows centric stuff I'm familiar with from Forms such as MessageBox.Show(); inside of my loop it interrupts the MainWindow and the textbox is updated..!

What exactly is in MessageBox.Show() that allows/forces/coerces the rendering to happen , and can I not just call that directly? The way I have gone about this seems to the most simple version of when you would need databinding to just work out of the box without any cumbersome work around.. hope I'm missing the easy button..

Any help would be of great value. Thanks in advance for your time.

public partial class MainWindow : Window{

private ExampleDataClass objClass = null;

public MainWindow()
{
    InitializeComponent();
    objClass = new ExampleDataClass();
    this.DataContext = objClass;
}

public int j = 0;

private string _someLocalString = "";

public string SomeLocalString
{
    get { return _someLocalString; }
    set { _someLocalString = value; }
}

public string strstr = ""; 


private void textBox_TextChanged(object sender, TextChangedEventArgs e)
{
    //MessageBox.Show(""); // this will make it work.. 
}

private void button_Click(object sender, RoutedEventArgs e)
{

    SomeLongRunningCode(out strstr);
}

public void SomeLongRunningCode(out string SomeProperty)
{
    for (int i = 1; i <= 600; i++)
    {
        SomeLocalString = i.ToString();
        objClass.X = _someLocalString;

        //   BindingOperations.GetBindingExpressionBase(textBox, TextBox.TextProperty).UpdateTarget();
        //    textBox.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
        //       new Action(delegate() { textBox.Text = i.ToString();}));
    }



    SomeProperty = "Exited SomeLongRunningCode";
}}}

<Window x:Class="DataBinding.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:DataBinding"
    mc:Ignorable="d"
    Title="MainWindow" Height="109.157" Width="176.303">
<Grid x:Name="myGrid">
    <TextBox x:Name="textBox" Text="{Binding X,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Focusable = "true" HorizontalAlignment="Left" Height="23" Margin="22,14,0,0" TextWrapping="Wrap"  VerticalAlignment="Top" Width="120" TextChanged="textBox_TextChanged" />
    <Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="24,46,0,0" VerticalAlignment="Top" Width="75" Click="button_Click"/>

</Grid>

public class ExampleDataClass : INotifyPropertyChanged
{

    private string _x = "";
    public string X
    {
        get { return _x;}
        set
        {
            if (_x != null)
            {
                _x = value;
                OnPropertyChanged("X");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(string info)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(info));
        }
    }

}}

Solution

  • textBox is not updating because the thread is blocked during the for loop.

    If you run SomeLongRunningCode asynchronously, you will see that your code works as intended.

    private void button_Click(object sender, RoutedEventArgs e)
    {
    
        Task.Run(() => SomeLongRunningCode(out strstr));
    }
    
    public void SomeLongRunningCode(out string SomeProperty)
    {
        for (int i = 1; i <= 600; i++)
        {
            SomeLocalString = i.ToString();
            objClass.X = _someLocalString;
            Thread.Sleep(100);   // Slowing down so we can see the text change
        }
    
    
    
            SomeProperty = "Exited SomeLongRunningCode";
    }