Silverlight Button Click - silverlight

I'm having problems getting the Silverlight Button Click event to immediately update a control's UI element and then continue doing some other process. For example, update the text of a control and then do some process. I've tried calling the UpdateLayout() method but that doesn't help.
Here is some sample code:
private void button1_Click(object sender, RoutedEventArgs e)
{
textBlock1.Text = "Testing";
textBlock1.UpdateLayout();
UpdateLayout();
Thread.Sleep(2000);
textBlock1.Text = "Done";
}
In that sample, the textBlock1 control will never display the text "Testing".

It's because you've blocked the UI thread with your Sleep statement which means that the text block won't update until after it's completed, but by that time you've set the text to "Done".

This doesn't work. The UI will block when you do not exit the method. This is why in Silverlight you usually do everything asynchronously:
private void button1_Click(object sender, RoutedEventArgs e)
{
textBlock1.Text = "Testing";
var myTask = /* ... */
myTask.Completed += new FancyDelegate(myTask_Completed);
}
private void myTask_Completed(object sender, RoutetEventArgs e)
{
textBlock1.Text = "Done.";
}
If your tasks do not have asynchronous functions, just wrap them. But be reminded, that when you want to change your textBlock1.Text property from another thread, you must invoke it with the Dispatcher.

Related

WPF - Datagrid selection changed with background worker

I am writing a program that reads information from a device through the serial port. I have a list of available devices in a datagrid. When the user clicks on a row, it fetches information from the device and displays it in a separate list. It usually takes about a second for the device to respond and the information to populate. However, during this second, the datagrid row does not highlight as selected. So it takes about a second from the time the mouse clicks on the datagrid row for it to actually show as highlighted/selected.
I thought a background worker thread would be the best thing to use for this, but I get the same results with the code below. Am I using it incorrectly, or is there something else I should be doing for selecting a datagrid row?
private void relayList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += GetLinks;
worker.RunWorkerAsync();
}
private void GetLinks(object sender, DoWorkEventArgs e)
{
//send message to viewModel and do time-consuming work here
}
BackgroundWorker has a RunWorkerCompleted method. It will run in the execution context of the UI thread.
There is also a result property that is used to pass a result to the next method which is the RunWorkerCompleted method.
private void yourMethod()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += DoWorkMethod;
worker.RunWorkerCompleted += RunWorkerCompletedMethod;
worker.RunWorkerAsync();
}
private void RunWorkerCompletedMethod(object sender, RunWorkerCompletedEventArgs e)
{
string result = (string)e.Result;
// do stuff here
}
private void DoWorkMethod(object sender, DoWorkEventArgs e)
{
e.Result = string.Empty; // Your device data
}
If you desperatly want to not use the completed method. Do not use dispatcher, instead use SynchronizationContext.
You will need to store SynchronizationContext.Current on a field when you first run your form but after that you can invoke whatever you need on the UI thread.

ManipulationStarted fails to activate callback method

I have a WPF Canvas with .NET-4.5.
I added events (which autocreated methods for) MouseLeftButtonDown and MouseDown. Using MessageBox, I have confirmed these methods are called when a user clicks on the canvas, but I can't find a way to get the mouse position from MouseButtonEventArgs.
When I added events (and autocreated methods for) ManipulationStarted and ManipulationStarting those MessageBoxes don't show up.
private void CenterCanvas_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
{
MessageBox.Show("Doesn't show up"); // never shows up
}
private void CenterCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Shows up"); // shows up, but can't seem to get click position
}
In order to get the mouse position from a MouseEventArgs you would have to call the GetPosition method.
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
var pos = e.GetPosition((IInputElement)sender);
System.Diagnostics.Trace.TraceInformation("MouseDown at {0}", pos);
}
For getting manipulation events you need to set IsManipulationEnabled to true. You may want to take a look at the Touch and Manipulation section in the MSDN Input Overview.

It is possible to create "new MouseButtonEventArgs" in Silverlight?

I'm newbie in Silverlight and I need to activate MouseRightButtonDown(object sender, MouseButtonEventArgs e) from an another event handler in my application.
I have found, that in WPF it is possible to do somthing like this:
public void OnContextMenuOpened(object sender, RoutedEventArgs e) {
MouseButtonEventArgs args = new MouseButtonEventArgs(
InputManager.Current.PrimaryMouseDevice,
0,
MouseButton.Right);
MouseRightButtonDown(sender, args);
}
But I have in Silverlight neither InputManager-Class nor MouseButton-Class... It is generally possible to realise something like that?
I want to do it, because I try to select an DataGridRow(within an custom control) with help of right-mouse-button. Without context menu it is easily possible, but when I switch context menu on, then context menu opens and event will not fired...
My code snippet:
public override void OnApplyTemplate() {
DataGrid = (DataGrid)GetTemplateChild("DataGrid");
DataGrid.MouseRightButtonDown += DataGridMouseRightButtonDown;
ContextMenu = (ContextMenu)GetTemplateChild("ContextMenu");
ContextMenu.Opened += OnContextMenuOpened;
}
private void DataGridMouseRightButtonDown(object sender, MouseButtonEventArgs e) {
//My code to select an DataGridRow
}
public void OnContextMenuOpened(object sender, RoutedEventArgs e) {
//This event-handler now will be always activated if I do
//right-mouse-button-click
}
Thanks a lot for help!
The Results of my research has shown, that it is impossible in silverlight -.-

What event can I change the caret in in a winforms maskedtextbox

Right now, I'm calling the win32 createcaret/showcaret in the keypress event of my masked textbox. That changes it fine. I want the caret to change when the box is entered, though, either by tab or by click.
Unfortunately the enter event or even the invalidate event aren't suitable places to change that caret. It doesn't change, maybe because they fire too early.
So anyway, how can I get the caret to change on textbox enter without handling it in the enter event?
You need to add DestroyCaret to your routine, too:
private void Form1_Load(object sender, EventArgs e)
{
textBox1.GotFocus += new EventHandler(textBox1_GotFocus);
textBox1.LostFocus += new EventHandler(textBox1_LostFocus);
}
private void textBox1_GotFocus(object sender, EventArgs e)
{
CreateCaret(textBox1.Handle, IntPtr.Zero, 6, textBox1.Height);
ShowCaret(textBox1.Handle);
}
private void textBox1_LostFocus(object sender, EventArgs e)
{
DestroyCaret();
}

UI update in WPF elements event handlers

There is a problem with UI update in WPF.
I have such code:
private void ButtonClick_EventHandler(object sender, RoutedEventArgs e)
{
Label.Visibility = Visibility.Visible;
TextBox.Text = "Processing...";
LongTimeMethod(); //some long operation
}
The problem is that until LongTimeMethod ends (that is event handler ends), Label.Visibility and TextBox.Text will not be changed.
I solved it like this so far:
private void ButtonClick_EventHandler(object sender, RoutedEventArgs e)
{
Label.Visibility = Visibility.Visible;
TextBox.Text = "Processing...";
Dispatcher.BeginInvoke(new Action(LongTimeMethod),
DispatcherPriority.Background);
}
Is there any other solution without using dispatcher invocation? Calling this.UpdateLayout() doesn't help.
With Dispatcher.BeginInvoke you are still using the UI thread for LongTimeMethod(). If this is not required (i.e. it is doing some kind of background processing) I would suggest using the TPL to run it on a background thread:
private void ButtonClick_EventHandler(object sender, RoutedEventArgs e)
{
Label.Visibility = Visibility.Visible;
TextBox.Text = "Processing...";
Task.Factory.StartNew(() => LongTimeMethod())
.ContinueWith(t =>
{
Dispatcher.BeginInvoke((Action)delegate()
{
TextBox.Text = "Done!";
});
});
}
With this method, the long running method is processed on a background thread (so the UI thread will be free to keep rendering and the app won't freeze up) and you can do anything that does alter the UI (such as updating the textbox text) on the UI Dispatcher when the background task completes
Visibility and Text are dependency properties which updated by dispatcher. Your solution is absolutely corrent, but my suggestion is to do it asynchronously.
On other hand, you might simulate Application.DoEvents in WPF (see the article).

Resources