WP7 controls: When to set VisualState after recovering from Tombstone? - windows-phone-7

My question is simple: WHEN (on what event?) can I be sure that a control has fully loaded and has its states and templates also?
Why am I asking:
I'm trying to restore the state of my own WP7 control after recovering from tombstone. This control looks like a calendar in a weekly view. In this calendar you can select many items displayed as colored Rectangles.
If I select any of them, and then go to tombstone and come back to the page, it seems like my control forgot which Rectangles were selected. In fact, it did NOT forget the data itself, but the Rectangles forgot their selected state.
After recovering from tombstone, I try to select the Rectangles by setting their VisualState to "Selected" (which works in any other scenario). I found out, that it fails, because VisualStateManager can't find the "Selected" state.
I know this is tricky, because when coming back from tombstone the controls do not build exactly as in any "normal" case. (for example Bindings and Templates do not apply in the same order) But up until now I could always trust, that when FrameworkElement.Loaded fired, I had my controls ready. Now it seems like VisualState is not. (I tried to set the state from Loaded event handler, but results are the same, VisualStateManager.GoToState returns with false.)
What more can I do?

This is a tricky one! I have also experienced issues where UI events fire before the UI itself is fully constructed, see this blog post for an example. My general approach to this is to handle the LayoutUpdated event, which fires each time the visual tree is updated. You will find that this event fires multiple times, both before and after the Loaded event.
When the Layoutupdated event fires, you can check whether the visual state change has worked, if so, no longer handle the event. If not, keep trying!
Within your loaded event, try the following:
// try to set the state
if (VisualStateManager.GoToState(myControl, "myState") == false)
{
// if failed, wait for the next LayoutUpdated event
EventHandler updateHandler = null;
updateHandler = (s, e2) =>
{
if (VisualStateManager.GoToState(myControl, "myState") == false)
{
myControl.LayoutUpdated -= updateHandler;
}
};
myControl.LayoutUpdated += updateHandler;
}

Related

Separating single clicks from click and hold

I need to implement a behavior:
when element clicked - one thing happens
but when it's clicked and held for more than one second, something else happens (e.g element becomes draggable) and then the first event never fires
I think I know how to catch click&hold type of events, but how to distinguish between first and second?
Can you show me how to do that using this jsbin. I already made the "click, hold & drag" part, except that it is still firing the 'click' event after dragging the element and it shouldn't.
again: element clicked - one event, click and hold - element is draggable (even after mouse up) and when clicked again it's back to normal (undraggable) state.
I am not looking for a trivial solution, it has to be built using Rx.Observable or at least Bacon's streamEvent object
Thank you
I think you were pretty close with your solution, but probably it is not possible to elegantly achieve what you want while using the browser's built-in click event.
HERE is my attempt to tackle your problem.
The main idea is to define your own click streams like so:
var clicks = downs.flatMapLatest(function(){
return ups.takeUntil(Rx.Observable.timer(250));
});
var longDownsStart = downs.flatMapLatest(function(){
return Rx.Observable.timer(1000).takeUntil(ups);
});
In case of clicks we wait max 250 ms after a mouse down for a mouse-up; in case of the latter we generate the event only if there was no mouse-up within 1000 ms.
There might be some corner cases in which the code does not work as intended.
Here is my proposed solution (with Bacon.js).

Intercepting and Disabling Global Mouse Events

I have a problem with my mouse. Every now and then it will double click when I only single click. I know this is a problem with the mouse, and I've contacted the manufacturer, still waiting for a reply. But in the meantime I was wondering if there was a way that I could find out when the left mouse button had been clicked twice within a very short period (probably 1-10 milliseconds) of time, and disable the second click.
I mostly know how to use hooks, so that's not the problem, my main question is how to stop an event from happening, if that's possible.
The information on how to prevent the mouse message from being processed is in the documentation of the "LowLevelMouseProc callback function" in MSDN:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644986(v=vs.85).aspx
Specifically, it says: "If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the rest of the hook chain or the target window procedure." So, if you know about windows hooks, you know how to do it.
EDIT: Actually, now that I think more about it, you don't want to discard any event. You simply want to transform the doubleclick event into just another left-button-down event. I believe you can do it from within the hook handler, and it will work. Have you tried it?
In C#'s WinForms, you write an event handler involving the mouse receiving a MouseEventArgs object. Inside it, you can access certain info such as the number of times it was clicked, for example.
protected void RowClicked(object sender, MouseEventArgs evt)
{
// Trigger it when the mouse was clicked only once
if( evt.Button.Clicks == 1 ) {
// ... more things ...
}
return;
}
Other GUI libraries have other possibilities. That said, your problem has nothing to do with GUI libraries. You have to change the sensitivity of your mouse, in the configuration options of your operating system. For example, in the Windows' control panel, you can change how much time has to pass between a click and another one to be considered a doble-click. In lUbuntu, you can do the very same, in System menu >> Preferences >> Keyboard and Mouse.

How to make it so events cannot occur while an event is running in DOJO?

Is there some way I can disable all events until an event is completed in DOJO? For instance I am fading elements and the user can click the event again and it will not complete the last event.
If you control all events that need to be disabled, you could try using a global variable as a "lock" - set it on when you start the animation (and have all events abort if they find this flag triggered) and unset it when it ends.
Javascript is not concurrent (so you don't need to worry about timing issues and having an "actual" lock) but perhaps the fading uses setTimeout behind the scenes (allowing other events to trigger before it is done). If this is the case, just remember that you would need to use the onEnd callback to properly detect when the anim is over
var lock = false;
function my_event_handler(evt){
if(lock) return; //someone else is using the lock;
//perhaps cancel event propagation as well?
lock = true;
dojo.anim({
...
onEnd: function(){
lock = false;
}
});
}
caveat: this is pseudocode off the top of my head. I haven't used dojo animations in a while if you didn't notice already :P
I'm not sure I understand what you mean by events here, but if you want to prevent interaction with elements on a page, you can put up a modal shield... basically a transparent DIV element to capture events, positioned over your content with a high z-index

WP7 Timepicker OnNavigatedTo fired again after finishing time selection

I have a page that I am navigating to that does some setup stuff via the 'OnNavigatedTo' event.
Thso page contains a TimePicker control and I have discovered that when I finish in the Timepicker control and focus returns back to my page it is again going through the 'OnNavigatedTo' event.
As a result is doing setup stuff again that is mucking things up, and if even has the same NavigationContext.QueryString as when I originally navigated to that page.
I assume I cannot avoid this event being called again - but is there any way to know that I have come here as a result of exiting the Timepicker control?
thanks
What about defining a bool in the class (instance-level, not static) that you set check in OnNavigatedTo -- if false, then do your work and set to true. Now, I'm not 100% sure that this works if you go back one level further and then tap on whatever brought up this page, so check that. Also, check to ensure everything works with tombstoning -- that's where you're more likely to have problems.
--randy

Changing ListBox selection is not moving changes from BindingSource to DataSet

The answer to this question may turn out to be, "Don't use typed DataSets without using the Binding Navigator."
I am curious, however, about the behavior I'm seeing.
So, I created a form where every control was dragged from the data sources explorer.
I deleted the Binding Navigator because it is ugly and inappropriate for this particular form.
I added a ListBox and set the DataSource to the BindingSource.
Notice that the ListBox is not bound, it is just filling itself from the BindingSource.
By some magic that I wasn't counting on, moving around in the ListBox is navigating the BindingSource and all other controls are updating accordingly.
I can make changes to the bound controls and explicitly call EndEdit on the BindingSource and then update the DataSource through the Table Adapter. Works great.
When I make changes in the bound controls and click a new option in the ListBox, I want to be able to check for changes and prompt to save or reset if there are any.
Here is the strange part that I haven't been able to figure out.
No matter what event I attach to, DataSet.HasChanges doesn't return true until the second ListBox change.
I've searched and tried dozens of suggestions, most of them ridiculous, but a few that seemed promising.
No luck.
Edit: It isn't the second click that is significant, it is when you click back on the original (edited) item.
Since asking the question, I've learned a bit more about BindingSources, DataSets and TableAdapters.
Here is what works:
private void MyListBox_Click(object sender, EventArgs e)
{
this.myBindingSource.EndEdit();
if (myDataSet.HasChanges())
{
if (MessageBox.Show("Save changes?", "Before moving on", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
myTableAdapter.Update(myDataSet.myDataTable);
}
else
{
myDataSet.RejectChanges();
}
}
}

Resources