Reputation: 55
I have a problem that's been bugging me for days, I've tried every option and I'm now resulting in posting my own question to find some specific help from you guys.
I need to update a TextBlock at the start of code block, which is run on a simple button click.
Here's my code:
private void NewProject(bool blnCopy = false, string strFileName = null)
{
if (App.ApplicationBusy == false)
{
App.ApplicationBusy = true;
try
{
Action action = delegate()
{
Cursor = Cursors.Wait;
lblStatus.Text = "Opening Project...";
};
Dispatcher.Invoke(DispatcherPriority.Send, action);
if (blnCopy == false) { Project = new GSProject((App.RecentProjectCount + 1)); }
if (Project != null)
{
Projects.Add(Project);
if (blnCopy == false)
{
if (strFileName == null)
{
Project.ProjectName = string.Format("GSProject{0}", Projects.Count.ToString());
Project.ProjectDescription = string.Format("{0} - HW GS Project", Project.ProjectName);
Project.LoadResource();
}
else
{
Project.Load(strFileName);
}
}
else
{
Project = Project.Copy();
}
p_objNewPane = objDocker.AddDocument(Project.ProjectDisplayName, Project);
if (p_objNewPane != null)
{
p_objNewPane.DataContext = Project;
BindingOperations.SetBinding(p_objNewPane, ContentPane.HeaderProperty, new Binding("ProjectDisplayName") { Source = Project });
p_objNewPane.Closing += new EventHandler<PaneClosingEventArgs>(ContentPane_Closing);
}
if (Project.CalculationExists == true)
{
InitializeCalculation(true);
}
}
tabStartPage.Visibility = Visibility.Collapsed;
objDocumentTabs.SelectedIndex = 0;
}
catch (Exception ex)
{
ModernDialog.ShowMessage(string.Format("An error has occurred:{0}{0}{1}", Environment.NewLine, ex.Message), "Error", MessageBoxButton.OK, Application.Current.MainWindow);
}
finally
{
App.ApplicationBusy = false;
Cursor = Cursors.Arrow;
AppStatus = "Ready";
p_objNewPane = null;
}
}
}
At the start of the try block, I need to update the TextBlock (lblStatus) to say what's going on. The void itself, NewProject, is on the MainWindow, and is called by a button click.
Can someone please give me an idea of where I'm going wrong? I've tried countless potential solutions, so please don't be offended if I get back to you saying I've tried it.
Regards, Tom.
Upvotes: 0
Views: 77
Reputation: 55
After a few painful days I managed to get this working. I was barking up the wrong tree completely by looking into Task Scheduling, etc. Instead all that was needed was a DependencyProperty.
XAML (Main Window):
<TextBlock x:Name="lblStatus"
Text="{Binding AppStatus, IsAsync=True}"
Grid.Column="0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontFamily="Segoe UI"
FontSize="12"
Foreground="White"
Margin="5, 0, 0, 0" />
C# (Main Window):
public string AppStatus
{
get { return (string)GetValue(AppStatusProperty); }
set { SetValue(AppStatusProperty, value); }
}
public static readonly DependencyProperty AppStatusProperty =
DependencyProperty.Register("AppStatus", typeof(string), typeof(MainWindow), new PropertyMetadata(null));
public void StatusBarUpdate(string strMainMessage)
{
Dispatcher.BeginInvoke((Action)(() => { AppStatus = strMainMessage; }));
}
I can then call the StatusBarUpdate
method at any time and it will asynchronously update the UI.
Upvotes: 1
Reputation: 14608
You haven't mentioned what exactly is the problem, but looking at the code I can guess that the textbox shows "Opening Project..." only after completion of your code or shows "Ready" if AppStatus
is doing the same thing.
If yes, the problem is that you are doing everything on the UI thread. Although you changed the text of the textbox, it will be rendered after your work is done, hence the problem. To fix this, you need to run the code from if (blnCopy == false)
to objDocumentTabs.SelectedIndex = 0;
on a worker thread. That will fix your problem.
You can use TPL for that and can also you .ContinueWith
with TaskScheduler.FromCurrentSynchronizationContext
and TaskContinuationOptions.OnlyOnRanToCompletion
to execute the finally block.
EDIT:
As you are not using MVVM, you will need a lot of Invoke
to make your code work. As I can see p_objNewPane is also an UI element just like Project
is a view property, it will be difficult to translate all that to TPL. You can leave code from p_objNewPane = ...
as it is (i.e. outside worker thread). That doesn't seem to be very cpu intensive except maybe InitializeCalculation
which you can run in another worker thread.
A better approach is that you use await/async methods to wait for all heavy lifting methods.
Upvotes: 0
Reputation: 1388
You are using WPF, Therefore implement
INotifyPropertyChanged
and use proper data binding.
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public string StatusText
{
get {return this.m_statusText;}
set
{
if (value != this.m_statusText)
{
this.m_statusText= value;
NotifyPropertyChanged("StatusText");
}
}
}
And in XAML
<TextBox Text="{Binding Path=StatusText}"/>
Upvotes: 0