ADBF
ADBF

Reputation: 93

PropertyChanged not updated in xaml unless there is a pause

This is a long question about a silly problem that is not vital to my application, but still very strange. I feel if I understand it it will help me understanding c#/wpf a lot bettre.

I'm working on a application to load excel file into mysql. In a log-textbox I want to show when the rows in the database are deleted. After loading the new data into the database the log-textbox should show a message with the number of rows affected.

The textbox binds to

<TextBox x:Name="ConnectionLogTbx" Text="{Binding ConnectionLogText}" /> 

The codebehind below (some lines omitted): ConnectionLogText is appended with a string. First a datetime + " deleted". The second time with the numbers of rows affected.

Inserting the database takes about 2 seconds. What I would expect is that the first logmessage appears, then a pause for two seconds ( when the new rows are inserted) and then the second log message. The funny thing is that the Textbox updates with both strings after the insert operation. No log-message apppears before the insert operation. The times shown are as expected with about 2 seconds between them.

However if I add a messagebox.show in the setter for the property ( and thus creating a pause ) the application behaves as expected. The first logmessage appears in the textbox, and after clicking the message box, the insertoperation takes place and after that the second log message appears.

It almost looks like WPF needs a break to update the textbox, but that is not consistent with what I understand about WPF.

Could someone help me?

public partial class MainWindow : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    private string connectionLogText ="";

    public string ConnectionLogText
        {
            get { return connectionLogText; }
            set
            {
                if (value != connectionLogText)
                {
                    connectionLogText = value;
                    OnPropertyChanged("ConnectionLogText");
                    //MessageBox.Show(""); //THIS IS THE MESSAGEBOX
                 }
            }

       }


    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }


    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
    }


    private void BrowseImportFile_Click(object sender, RoutedEventArgs e)
    {
        OpenFileDialog openFileDialog = new OpenFileDialog();
        if (openFileDialog.ShowDialog() == true)
        {
            ImportFilePathTbx.Text = openFileDialog.FileName;
            ImportFileBtn.IsEnabled = true;
        }
    }

    private void ImportFileBtn_Click(object sender, RoutedEventArgs e)
    {
         string connString = 
      ConfigurationManager.ConnectionStrings["connSTring"].ConnectionString;

        MySqlConnection conn = new MySqlConnection(connString);

        conn.Open();
       //here the content of the current db table is deleted
        conn.Close();
        ConnectionLogText += DateTime.Now.ToString("hh:mm:ss.fff") + " 
Deleted" + "\r\n";

        conn.Open();

        int numberOfRowsAffected = 0;
        foreach (DataRow dataRow in table.Rows)
       {
            //new data inserted into database numberOfRowsAffected++;
        }
        conn.Close();

        ConnectionLogText += DateTime.Now.ToString("hh:mm:ss.fff") + " " + 
numberOfRowsAffected +  " rows inserted" + "\r\n" ;
        }
 }

Upvotes: 0

Views: 62

Answers (1)

mm8
mm8

Reputation: 169270

You can't update the TextBlock and read records from a database simultaneously on the same thread.

You should perform the database operations on a background thread. The easiest way to do this use the Task Parallel Library (TPL):

private async void ImportFileBtn_Click(object sender, RoutedEventArgs e)
{
    string connString = ConfigurationManager.ConnectionStrings["connSTring"].ConnectionString;
    await Task.Run(() =>
    {
        using (SqlConnection conn = new SqlConnection(connString))
        {
            conn.Open();
            //here the content of the current db table is deleted
            conn.Close();
        }
    });

    ConnectionLogText += DateTime.Now.ToString("hh:mm:ss.fff") + " Deleted" + "\r\n";

    int numberOfRowsAffected = 0;
    await Task.Run(() =>
    {
        conn.Open();
        foreach (DataRow dataRow in table.Rows)
        {
            //new data inserted into database numberOfRowsAffected++;
        }
        conn.Close();
    });

    ConnectionLogText += DateTime.Now.ToString("hh:mm:ss.fff") + " " + numberOfRowsAffected + " rows inserted" + "\r\n";
}

Upvotes: 2

Related Questions