SetCompatibleTextRenderingDefault in .NET Class Library containing a form - vb.net

I have a .net class library with a com class that calls a form.
I want to to SetCompatibleTextRenderingDefault(false) to ensure the form fonts look nice.
If I run the command in the class constructor I get the following error:
SetCompatibleTextRenderingDefault must be called before the first IWin32Window object is created in the application.
Where can/should I run this? Surely there is no earlier place than sub New!
Thank in advance
Jon
Edit1: To clarify, I get this error when initiating the class from a .net test harness, if I call it from a VB6 app then I simply get "Automation Error"
Edit2: Is the answer that I cannot use SetCompatibleTextRenderingDefault in a com class when calling from a vb6 app?? Maybe it's the "parent" app that needs to call this method and as such a vb6 app cannot?
Edit3: Maybe I am asking this question in the wrong way! - Maybe the question is: how can I make the fonts look nice in a .net class library form called from a vb6 app?

A possible workaround would be to set the property manually on all buttons and labels in the form constructor:
public Form1()
{
InitializeComponent();
DisableCompatibleTextRendering(this);
}
private static void DisableCompatibleTextRendering(Control c)
{
var button = (c as ButtonBase);
var label = (c as Label);
if (button != null)
{
button.UseCompatibleTextRendering = false;
}
if (label != null)
{
label.UseCompatibleTextRendering = false;
}
foreach (var child in c.Controls.Cast<Control>())
{
DisableCompatibleTextRendering(child);
}
}

Place this inside the application startup code before the first window is created. Under C# this would be the main routine that then creates the initial window.

Related

MultiThreading from same Textbox doing website request [duplicate]

I have a scenario. (Windows Forms, C#, .NET)
There is a main form which hosts some user control.
The user control does some heavy data operation, such that if I directly call the UserControl_Load method the UI become nonresponsive for the duration for load method execution.
To overcome this I load data on different thread (trying to change existing code as little as I can)
I used a background worker thread which will be loading the data and when done will notify the application that it has done its work.
Now came a real problem. All the UI (main form and its child usercontrols) was created on the primary main thread. In the LOAD method of the usercontrol I'm fetching data based on the values of some control (like textbox) on userControl.
The pseudocode would look like this:
CODE 1
UserContrl1_LoadDataMethod()
{
if (textbox1.text == "MyName") // This gives exception
{
//Load data corresponding to "MyName".
//Populate a globale variable List<string> which will be binded to grid at some later stage.
}
}
The Exception it gave was
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on.
To know more about this I did some googling and a suggestion came up like using the following code
CODE 2
UserContrl1_LoadDataMethod()
{
if (InvokeRequired) // Line #1
{
this.Invoke(new MethodInvoker(UserContrl1_LoadDataMethod));
return;
}
if (textbox1.text == "MyName") // Now it won't give an exception
{
//Load data correspondin to "MyName"
//Populate a globale variable List<string> which will be binded to grid at some later stage
}
}
But it still seems that I've come back to square one. The Application again
becomes unresponsive. It seems to be due to the execution of line #1 if condition. The loading task is again done by the parent thread and not the third that I spawned.
I don't know whether I perceived this right or wrong.
How do I resolve this and also what is the effect of execution of Line#1 if block?
The situation is this: I want to load data into a global variable based on the value of a control. I don't want to change the value of a control from the child thread. I'm not going to do it ever from a child thread.
So only accessing the value so that the corresponding data can be fetched from the database.
As per Prerak K's update comment (since deleted):
I guess I have not presented the question properly.
Situation is this: I want to load data into a global variable based on the value of a control. I don't want to change the value of a control from the child thread. I'm not going to do it ever from a child thread.
So only accessing the value so that corresponding data can be fetched from the database.
The solution you want then should look like:
UserContrl1_LOadDataMethod()
{
string name = "";
if(textbox1.InvokeRequired)
{
textbox1.Invoke(new MethodInvoker(delegate { name = textbox1.text; }));
}
if(name == "MyName")
{
// do whatever
}
}
Do your serious processing in the separate thread before you attempt to switch back to the control's thread. For example:
UserContrl1_LOadDataMethod()
{
if(textbox1.text=="MyName") //<<======Now it wont give exception**
{
//Load data correspondin to "MyName"
//Populate a globale variable List<string> which will be
//bound to grid at some later stage
if(InvokeRequired)
{
// after we've done all the processing,
this.Invoke(new MethodInvoker(delegate {
// load the control with the appropriate data
}));
return;
}
}
}
Threading Model in UI
Please read the Threading Model in UI applications (old VB link is here) in order to understand basic concepts. The link navigates to page that describes the WPF threading model. However, Windows Forms utilizes the same idea.
The UI Thread
There is only one thread (UI thread), that is allowed to access System.Windows.Forms.Control and its subclasses members.
Attempt to access member of System.Windows.Forms.Control from different thread than UI thread will cause cross-thread exception.
Since there is only one thread, all UI operations are queued as work items into that thread:
If there is no work for UI thread, then there are idle gaps that can be used by a not-UI related computing.
In order to use mentioned gaps use System.Windows.Forms.Control.Invoke or System.Windows.Forms.Control.BeginInvoke methods:
BeginInvoke and Invoke methods
The computing overhead of method being invoked should be small as well as computing overhead of event handler methods because the UI thread is used there - the same that is responsible for handling user input. Regardless if this is System.Windows.Forms.Control.Invoke or System.Windows.Forms.Control.BeginInvoke.
To perform computing expensive operation always use separate thread. Since .NET 2.0 BackgroundWorker is dedicated to performing computing expensive operations in Windows Forms. However in new solutions you should use the async-await pattern as described here.
Use System.Windows.Forms.Control.Invoke or System.Windows.Forms.Control.BeginInvoke methods only to update a user interface. If you use them for heavy computations, your application will block:
Invoke
System.Windows.Forms.Control.Invoke causes separate thread to wait till invoked method is completed:
BeginInvoke
System.Windows.Forms.Control.BeginInvoke doesn't cause the separate thread to wait till invoked method is completed:
Code solution
Read answers on question How to update the GUI from another thread in C#?.
For C# 5.0 and .NET 4.5 the recommended solution is here.
You only want to use Invoke or BeginInvoke for the bare minimum piece of work required to change the UI. Your "heavy" method should execute on another thread (e.g. via BackgroundWorker) but then using Control.Invoke/Control.BeginInvoke just to update the UI. That way your UI thread will be free to handle UI events etc.
See my threading article for a WinForms example - although the article was written before BackgroundWorker arrived on the scene, and I'm afraid I haven't updated it in that respect. BackgroundWorker merely simplifies the callback a bit.
I know its too late now. However even today if you are having trouble accessing cross thread controls? This is the shortest answer till date :P
Invoke(new Action(() =>
{
label1.Text = "WooHoo!!!";
}));
This is how i access any form control from a thread.
I have had this problem with the FileSystemWatcher and found that the following code solved the problem:
fsw.SynchronizingObject = this
The control then uses the current form object to deal with the events, and will therefore be on the same thread.
I find the check-and-invoke code which needs to be littered within all methods related to forms to be way too verbose and unneeded. Here's a simple extension method which lets you do away with it completely:
public static class Extensions
{
public static void Invoke<TControlType>(this TControlType control, Action<TControlType> del)
where TControlType : Control
{
if (control.InvokeRequired)
control.Invoke(new Action(() => del(control)));
else
del(control);
}
}
And then you can simply do this:
textbox1.Invoke(t => t.Text = "A");
No more messing around - simple.
Controls in .NET are not generally thread safe. That means you shouldn't access a control from a thread other than the one where it lives. To get around this, you need to invoke the control, which is what your 2nd sample is attempting.
However, in your case all you've done is pass the long-running method back to the main thread. Of course, that's not really what you want to do. You need to rethink this a little so that all you're doing on the main thread is setting a quick property here and there.
The cleanest (and proper) solution for UI cross-threading issues is to use SynchronizationContext, see Synchronizing calls to the UI in a multi-threaded application article, it explains it very nicely.
Follow the simplest (in my opinion) way to modify objects from another thread:
using System.Threading.Tasks;
using System.Threading;
namespace TESTE
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Action<string> DelegateTeste_ModifyText = THREAD_MOD;
Invoke(DelegateTeste_ModifyText, "MODIFY BY THREAD");
}
private void THREAD_MOD(string teste)
{
textBox1.Text = teste;
}
}
}
A new look using Async/Await and callbacks. You only need one line of code if you keep the extension method in your project.
/// <summary>
/// A new way to use Tasks for Asynchronous calls
/// </summary>
public class Example
{
/// <summary>
/// No more delegates, background workers etc. just one line of code as shown below
/// Note it is dependent on the XTask class shown next.
/// </summary>
public async void ExampleMethod()
{
//Still on GUI/Original Thread here
//Do your updates before the next line of code
await XTask.RunAsync(() =>
{
//Running an asynchronous task here
//Cannot update GUI Thread here, but can do lots of work
});
//Can update GUI/Original thread on this line
}
}
/// <summary>
/// A class containing extension methods for the Task class
/// Put this file in folder named Extensions
/// Use prefix of X for the class it Extends
/// </summary>
public static class XTask
{
/// <summary>
/// RunAsync is an extension method that encapsulates the Task.Run using a callback
/// </summary>
/// <param name="Code">The caller is called back on the new Task (on a different thread)</param>
/// <returns></returns>
public async static Task RunAsync(Action Code)
{
await Task.Run(() =>
{
Code();
});
return;
}
}
You can add other things to the Extension method such as wrapping it in a Try/Catch statement, allowing caller to tell it what type to return after completion, an exception callback to caller:
Adding Try Catch, Auto Exception Logging and CallBack
/// <summary>
/// Run Async
/// </summary>
/// <typeparam name="T">The type to return</typeparam>
/// <param name="Code">The callback to the code</param>
/// <param name="Error">The handled and logged exception if one occurs</param>
/// <returns>The type expected as a competed task</returns>
public async static Task<T> RunAsync<T>(Func<string,T> Code, Action<Exception> Error)
{
var done = await Task<T>.Run(() =>
{
T result = default(T);
try
{
result = Code("Code Here");
}
catch (Exception ex)
{
Console.WriteLine("Unhandled Exception: " + ex.Message);
Console.WriteLine(ex.StackTrace);
Error(ex);
}
return result;
});
return done;
}
public async void HowToUse()
{
//We now inject the type we want the async routine to return!
var result = await RunAsync<bool>((code) => {
//write code here, all exceptions are logged via the wrapped try catch.
//return what is needed
return someBoolValue;
},
error => {
//exceptions are already handled but are sent back here for further processing
});
if (result)
{
//we can now process the result because the code above awaited for the completion before
//moving to this statement
}
}
This is not the recommended way to solve this error but you can suppress it quickly, it will do the job . I prefer this for prototypes or demos . add
CheckForIllegalCrossThreadCalls = false
in Form1() constructor .
You need to look at the Backgroundworker example:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
Especially how it interacts with the UI layer. Based on your posting, this seems to answer your issues.
Here is an alternative way if the object you are working with doesn't have
(InvokeRequired)
This is useful if you are working with the main form in a class other than the main form with an object that is in the main form, but doesn't have InvokeRequired
delegate void updateMainFormObject(FormObjectType objectWithoutInvoke, string text);
private void updateFormObjectType(FormObjectType objectWithoutInvoke, string text)
{
MainForm.Invoke(new updateMainFormObject(UpdateObject), objectWithoutInvoke, text);
}
public void UpdateObject(ToolStripStatusLabel objectWithoutInvoke, string text)
{
objectWithoutInvoke.Text = text;
}
It works the same as above, but it is a different approach if you don't have an object with invokerequired, but do have access to the MainForm
I found a need for this while programming an iOS-Phone monotouch app controller in a visual studio winforms prototype project outside of xamarin stuidio. Preferring to program in VS over xamarin studio as much as possible, I wanted the controller to be completely decoupled from the phone framework. This way implementing this for other frameworks like Android and Windows Phone would be much easier for future uses.
I wanted a solution where the GUI could respond to events without the burden of dealing with the cross threading switching code behind every button click. Basically let the class controller handle that to keep the client code simple. You could possibly have many events on the GUI where as if you could handle it in one place in the class would be cleaner. I am not a multi theading expert, let me know if this is flawed.
public partial class Form1 : Form
{
private ExampleController.MyController controller;
public Form1()
{
InitializeComponent();
controller = new ExampleController.MyController((ISynchronizeInvoke) this);
controller.Finished += controller_Finished;
}
void controller_Finished(string returnValue)
{
label1.Text = returnValue;
}
private void button1_Click(object sender, EventArgs e)
{
controller.SubmitTask("Do It");
}
}
The GUI form is unaware the controller is running asynchronous tasks.
public delegate void FinishedTasksHandler(string returnValue);
public class MyController
{
private ISynchronizeInvoke _syn;
public MyController(ISynchronizeInvoke syn) { _syn = syn; }
public event FinishedTasksHandler Finished;
public void SubmitTask(string someValue)
{
System.Threading.ThreadPool.QueueUserWorkItem(state => submitTask(someValue));
}
private void submitTask(string someValue)
{
someValue = someValue + " " + DateTime.Now.ToString();
System.Threading.Thread.Sleep(5000);
//Finished(someValue); This causes cross threading error if called like this.
if (Finished != null)
{
if (_syn.InvokeRequired)
{
_syn.Invoke(Finished, new object[] { someValue });
}
else
{
Finished(someValue);
}
}
}
}
Simple and re-usable way to work around this problem.
Extension Method
public static class FormExts
{
public static void LoadOnUI(this Form frm, Action action)
{
if (frm.InvokeRequired) frm.Invoke(action);
else action.Invoke();
}
}
Sample Usage
private void OnAnyEvent(object sender, EventArgs args)
{
this.LoadOnUI(() =>
{
label1.Text = "";
button1.Text = "";
});
}
Along the same lines as previous answers,
but a very short addition that Allows to use all Control properties without having cross thread invokation exception.
Helper Method
/// <summary>
/// Helper method to determin if invoke required, if so will rerun method on correct thread.
/// if not do nothing.
/// </summary>
/// <param name="c">Control that might require invoking</param>
/// <param name="a">action to preform on control thread if so.</param>
/// <returns>true if invoke required</returns>
public bool ControlInvokeRequired(Control c, Action a)
{
if (c.InvokeRequired) c.Invoke(new MethodInvoker(delegate
{
a();
}));
else return false;
return true;
}
Sample Usage
// usage on textbox
public void UpdateTextBox1(String text)
{
//Check if invoke requied if so return - as i will be recalled in correct thread
if (ControlInvokeRequired(textBox1, () => UpdateTextBox1(text))) return;
textBox1.Text = ellapsed;
}
//Or any control
public void UpdateControl(Color c, String s)
{
//Check if invoke requied if so return - as i will be recalled in correct thread
if (ControlInvokeRequired(myControl, () => UpdateControl(c, s))) return;
myControl.Text = s;
myControl.BackColor = c;
}
this.Invoke(new MethodInvoker(delegate
{
//your code here;
}));
For example to get the text from a Control of the UI thread:
Private Delegate Function GetControlTextInvoker(ByVal ctl As Control) As String
Private Function GetControlText(ByVal ctl As Control) As String
Dim text As String
If ctl.InvokeRequired Then
text = CStr(ctl.Invoke(
New GetControlTextInvoker(AddressOf GetControlText), ctl))
Else
text = ctl.Text
End If
Return text
End Function
Same question : how-to-update-the-gui-from-another-thread-in-c
Two Ways:
Return value in e.result and use it to set yout textbox value in backgroundWorker_RunWorkerCompleted event
Declare some variable to hold these kind of values in a separate class (which will work as data holder) . Create static instance of this class adn you can access it over any thread.
Example:
public class data_holder_for_controls
{
//it will hold value for your label
public string status = string.Empty;
}
class Demo
{
public static data_holder_for_controls d1 = new data_holder_for_controls();
static void Main(string[] args)
{
ThreadStart ts = new ThreadStart(perform_logic);
Thread t1 = new Thread(ts);
t1.Start();
t1.Join();
//your_label.Text=d1.status; --- can access it from any thread
}
public static void perform_logic()
{
//put some code here in this function
for (int i = 0; i < 10; i++)
{
//statements here
}
//set result in status variable
d1.status = "Task done";
}
}
Simply use this:
this.Invoke((MethodInvoker)delegate
{
YourControl.Property= value; // runs thread safe
});
Action y; //declared inside class
label1.Invoke(y=()=>label1.Text="text");
There are two options for cross thread operations.
Control.InvokeRequired Property
and second one is to use
SynchronizationContext Post Method
Control.InvokeRequired is only useful when working controls inherited from Control class while SynchronizationContext can be used anywhere. Some useful information is as following links
Cross Thread Update UI | .Net
Cross Thread Update UI using SynchronizationContext | .Net

MvvmCross and back button in Windows Phone app

I'm building a Windows Phone app (8.1 using WinRT) using MvvmCross. To navigate to a new view I using ShowViewModel(). But when I hit the back button on the phone the app is closing instead of navigating back to the first view. How can I do it I want to return to the first view when I hitting the back button?
I solved it to use a interface in my viewmodel with a backbutton event, then I wrote a client speific implementation of it. In the viewmodel I handle the event and called the close method in the my base class MvxViewModel. Read more about my solution on my blog, http://danielhindrikes.se/windows-phone/handle-windows-phone-back-button-pressed-when-using-mvvm/
Here's a simpler solution. Create a base type for all your WP pages that derives from MvxWindowsPage. Then, handle the back key there and route the proper information to your VM:
public abstract class MyBaseView : MvxWindowsPage {
public MyBaseView() {
this.InitializeComponent();
HardwareButtons.BackPressed += HardwareButtons_BackPressed;
}
void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e) {
if (Frame.CanGoBack) {
var vm = ViewModel as MyBaseViewModel;
if (vm != null) {
e.Handled = true;
vm.GoBackCommand.Execute(null);
}
}
}
}
Now, you also have to make sure that you have a base viewmodel which derives from MvxViewModel and from which you derive all your VMs. That base VM should have a GoBackCommand observable property, and executing that command should do a simple Close(this).
To see what's going on under the hood, see this related question: Windows Phone 8.1 Universal App terminates on navigating back from second page?
EDIT
Fixed declaration.

Flow of initializing objects in XAML?

I'm not sure but from my hours of debugging, this should be the best description of my problem I can give.
I'm creating a WinRT app, there are two pages- Main Page and Details Page. Inside Main Page constructor, I have initialized a listbox. On click of any of the element of listbox, user is taken to the Details page.
I'm just learning all this and design may not be best but here is what I did.
I took a static variable in MainPage.cs, and set it to point to the element which is clicked by the user. Now in the constructor of the Details page, I used this static variable to set the datacontext of Details Page itself.
What flow I'm expecting is:-
MainPage is created first. Listbox is setup.
User will click on any of the element of listbox. Itemclick event handler runs. It will set the static variable (of Mainpage.cs) to hold the infomation which item is clicked and navigate user to the Details page.
In Details page constructor, I have set the datacontext to point to some information based on the value of static variable mentioned in the previous step.
It works for most of the times, but once in like every 5 times, The Details page constructor throws an exception stating the static variable is not initialized yet. Why is Details page's constructor running when I'm starting the app? and why only sometimes? Do I need to set DataContext of Details Page in some other method instead of constructor?
The code is somewhat complex and too much in terms of domain of the problem so I'm avoiding posting it. But if I'm failing to explain the problem please tell, I'll post it keeping it as related as I can.
CODE:-
This is the method called when an item in listbox is clicked--will take user to the Details page.
private void overviewlistbox_Tapped_1(object sender, TappedRoutedEventArgs e)
{
MatchOverview selectedmatch = (sender as ListBox).SelectedItem as MatchOverview;
matchFullDetails = new ObservableCollection<Match>();
foreach (Match m in UpdateController.matchList)
{
if (m.matchDescription == selectedmatch.matchDesc)
{
matchFullDetails.Add(m);
break;
}
}
if(!(matchFullDetails.Count == 0))
this.Frame.Navigate(typeof(Details));
}
This is the constructor for Main Page:-
public static ObservableCollection<Match> matchFullDetails;
public MainPage()
{
matchFullDetails = new ObservableCollection<Match>();
this.InitializeComponent();
UpdateController update = new UpdateController(); // Creating new object will update the overview_list of UpdateController(static list).
overviewlistbox.ItemsSource = UpdateController.overview_list;
}
And this is the code for constructor of details page, where the exception occurs:-
public static ObservableCollection<Match> matchdetails = new ObservableCollection<Match>();
DispatcherTimer dtm_detailspage = null;
public Details()
{
this.InitializeComponent();
matchdetails = MainPage.matchFullDetails; // matchdetails.Last<>() is take because we only need item which is added latest to the collection.
if (matchdetails.Last<Match>().type == "TEST") // Exception is thrown here--Initialization
// error. When I check MainPage.matchFullDetails,
// no data is shown which means its not yet
// initialized. Also the exception is thrown either at
// the start of the app, or when details page is visited. That too once in 4-5 times, not always.
{
matchdetails.Add(matchdetails.First<Match>() as TestMatch);
}
if (matchdetails.Last<Match>().type == "ODI")
{
matchdetails.Add(matchdetails.Last<Match>() as ODIMatch);
}
if (matchdetails.Last<Match>().type == "T20")
{
matchdetails.Add(matchdetails.Last<Match>() as T20Match);
}
}
Exception Screenshot:-
Call Stack data on bug encounter:-
[Cricket Expert.exe!Cricket_Expert.Details.Details() Line 33 + 0x5 bytes
[External Code]
Cricket Expert.exe!Cricket_Expert.Common.SuspensionManager.RestoreFrameNavigationState(Windows.UI.Xaml.Controls.Frame frame) Line 236 + 0x5 bytes
Cricket Expert.exe!Cricket_Expert.Common.SuspensionManager.RestoreAsyn() Line 124 0x8 bytes
Cricket Expert.exe!Cricket_Expert.App.OnLaunched(Windows.ApplicationModel.Activation.LaunchActivatedEventArgs args) Line 74 + 0x5 bytes
[External Code]
MAJOR UPDATE:
I finally found the flaw. If the Details page is still active, and the app is restarted, the problem occurs.
Is there a solution to this problem??
You can pass information on what needs to be displayed on the Details page through the Navigate call and set the DataContext in OnNavigatedTo override to avoid using static variables. Pages don't get created unless you do it specifically e.g. by navigating to one. They might not be recreated if a page has NavigationCacheMode changed from the default (Disabled) so instances of the page can be reused during navigation calls. Ultimately it's hard to say what's wrong but it seems like something in your code and we couldn't help you if you don't share a sample that reproduces the problem.
*EDIT
One way to debug Details being created before MainPage would be to add this code at the beginning of the Details constructor:
if (MainPage.matchFullDetails == null)
{
System.Diagnostics.Debugger.Break();
}
Then look at the Call Stack panel in Visual Studio to see how it gets constructed.
One way to see if matchFullDetails is ever set to null is to search for its assignment (put a cursor on matchFullDetails in Visual Studio code editor and hit Shift+F12).
Another way would be to make matchFullDetails into a property and test it like this:
private static ObservableCollection<Match> _matchFullDetails;
public static ObservableCollection<Match> matchFullDetails
{
get
{
return _matchFullDetails;
}
set
{
if (value == null)
{
System.Diagnostics.Debugger.Break();
}
_matchFullDetails = value;
}
}
*EDIT 2
You can initialize your static property in a static constructor like this:
public static ObservableCollection<Match> matchFullDetails;
static MainPage()
{
matchFullDetails = new ObservableCollection<Match>();
}
public MainPage()
{
this.InitializeComponent();
UpdateController update = new UpdateController(); // Creating new object will update the overview_list of UpdateController(static list).
overviewlistbox.ItemsSource = UpdateController.overview_list;
}
this will prevent the null reference exception but won't fix your problem overall. When your app gets suspended and resumed - you have to restore the full state and it seems like your matchFullDetails collection would need to be serialized and saved to disk when your app gets suspended. Alternatively you might simply ignore the suspension manager call in App.xaml.cs and always start on home page, though that's not a very good experience and I am not sure if it satisfies app certification.

Metro c++ async programming and UI updating. My technique?

The problem: I'm crashing when I want to render my incoming data which was retrieved asynchronously.
The app starts and displays some dialog boxes using XAML. Once the user fills in their data and clicks the login button, the XAML class has in instance of a worker class that does the HTTP stuff for me (asynchronously using IXMLHTTPRequest2). When the app has successfully logged in to the web server, my .then() block fires and I make a callback to my main xaml class to do some rendering of the assets.
I am always getting crashes in the delegate though (the main XAML class), which leads me to believe that I cannot use this approach (pure virtual class and callbacks) to update my UI. I think I am inadvertently trying to do something illegal from an incorrect thread which is a byproduct of the async calls.
Is there a better or different way that I should be notifying the main XAML class that it is time for it to update it's UI? I am coming from an iOS world where I could use NotificationCenter.
Now, I saw that Microsoft has it's own Delegate type of thing here: http://msdn.microsoft.com/en-us/library/windows/apps/hh755798.aspx
Do you think that if I used this approach instead of my own callbacks that it would no longer crash?
Let me know if you need more clarification or what not.
Here is the jist of the code:
public interface class ISmileServiceEvents
{
public: // required methods
virtual void UpdateUI(bool isValid) abstract;
};
// In main XAML.cpp which inherits from an ISmileServiceEvents
void buttonClick(...){
_myUser->LoginAndGetAssets(txtEmail->Text, txtPass->Password);
}
void UpdateUI(String^ data) // implements ISmileServiceEvents
{
// This is where I would render my assets if I could.
// Cannot legally do much here. Always crashes.
// Follow the rest of the code to get here.
}
// In MyUser.cpp
void LoginAndGetAssets(String^ email, String^ password){
Uri^ uri = ref new URI(MY_SERVER + "login.json");
String^ inJSON = "some json input data here"; // serialized email and password with other data
// make the HTTP request to login, then notify XAML that it has data to render.
_myService->HTTPPostAsync(uri, json).then([](String^ outputJson){
String^ assets = MyParser::Parse(outputJSON);
// The Login has returned and we have our json output data
if(_delegate)
{
_delegate->UpdateUI(assets);
}
});
}
// In MyService.cpp
task<String^> MyService::HTTPPostAsync(Uri^ uri, String^ json)
{
return _httpRequest.PostAsync(uri,
json->Data(),
_cancellationTokenSource.get_token()).then([this](task<std::wstring> response)
{
try
{
if(_httpRequest.GetStatusCode() != 200) SM_LOG_WARNING("Status code=", _httpRequest.GetStatusCode());
String^ j = ref new String(response.get().c_str());
return j;
}
catch (Exception^ ex) .......;
return ref new String(L"");
}, task_continuation_context::use_current());
}
Edit: BTW, the error I get when I go to update the UI is:
"An invalid parameter was passed to a function that considers invalid parameters fatal."
In this case I am just trying to execute in my callback is
txtBox->Text = data;
It appears you are updating the UI thread from the wrong context. You can use task_continuation_context::use_arbitrary() to allow you to update the UI. See the "Controlling the Execution Thread" example in this document (the discussion of marshaling is at the bottom).
So, it turns out that when you have a continuation, if you don't specify a context after the lambda function, that it defaults to use_arbitrary(). This is in contradiction to what I learned in an MS video.
However by adding use_currrent() to all of the .then blocks that have anything to do with the GUI, my error goes away and everything is able to render properly.
My GUI calls a service which generates some tasks and then calls to an HTTP class that does asynchronous stuff too. Way back in the HTTP classes I use use_arbitrary() so that it can run on secondary threads. This works fine. Just be sure to use use_current() on anything that has to do with the GUI.
Now that you have my answer, if you look at the original code you will see that it already contains use_current(). This is true, but I left out a wrapping function for simplicity of the example. That is where I needed to add use_current().

Simple example of DispatcherHelper

I'm trying to figure out how can I use DispatcherHelperftom MVVM light toolkit in SL, but I can't find any example.
From home page of this framework I know that
DispatcherHelper class, a lightweight class helping you to create
multithreaded applications.
But I don't know how to use it.
How and for what I can use it?
You only need the DispatcherHelper when yo want to make changes to components on your UI thread, from code that runs on a different thread. E.g. in an Silverlight application you call a web service to retrieve some data asynchroneously, and now want to inform the Ui that the data is present via a OnNotifyPropertyChanged event.
First you have to initialize the DispatcherHelper. In Silverlight you do this in Application_Startup:
//initialize Dispatch helper
private void Application_Startup( object sender, StartupEventArgs e) {
RootVisual = new MainPage();
DispatcherHelper.Initialize();
}
In WPF the initialization is done in the static constructor of you App class:
static App() {
DispatcherHelper.Initialize();
}
Then in your event, handling the completion of your asnc call, use the following code to call RaisePropertyChanged on the UI thread:
DispatcherHelper.CheckBeginInvokeOnUI(
() => RaisePropertyChanged(PowerStatePropertyName)
);
DispatcherHelper.BeginInvokeOnUl expects an Action so you can use any code in here just use
DispatcherHelper.CheckBeginInvokeOnUI(
() => { /* complex code goes in here */ }
);
to do more complex tasks.