Change Background of WP7 Application if Theme is altered - windows-phone-7

I need to change the Background Image of my Application if user changes theme from "Light" to "Dark" or vice-vesa in code behind. I hope these should be done in Page Loded event

#TimDams pointed you to one of the nice ways to detect what-theme-is-now-set, but I didn't notice there any information how to detect a change to the theme during the application runtime. The user could start your app, then bump forward to the menu, change the theme, and get back to your app. While you may think that your app will be tombstoned and then restarted and renavigated to your page with full cycle with all pageloads -- it is not 100% true.
Firstly, the PageLoaded is NOT a good place to do the initial check-and-set-styles, because, if you get that event called, then the page, probably, has already rendered once. If I remember well, the PageLoaded is invoked just after the first render. If this is true, then you will have to detect the colors earlier, for example in the LayoutUpdated (warning: this event is a great spammer. I mean, it gets called gazillions times. Attach a single-shot handler, you know, such that will instantly unattach-self on first invocation). Maybe you will be able to do it in the Page's .ctor, just after InitializeComponent. Or in the OnApplyTemplate or MeasureOverride, or at least ArrangeOverride -- the visuals should be mostly/fully available there.
Buuuut. I've intentionally 'bolded-out' the word "initial". With Mango, there's some multitasking getting more and more common, but even the pre-Mango 7.0 version does not guarantee that your app will be tombstoned. From my observations in early 7.0, for example, starting the MediaPlayer from WebBrowser component does not tombstone your app:) If you have some time to read, check WP7 recover from Tombstone and return to page for details on the "pause" vs "tombstone".
Anyways, if your app gets "paused" and the user switches themes in the meantime, I think (I've NOT checked) that your page will (in most of the cases) be just temporarily hidden and upon returning to the screen, it will probably not be re-created and will not be re-(Page)Loaded. If it is true, then you will have not so easy problem to solve, because your app may be paused, the OS rethemed, and your app unpased virtually in any moment of time and the only events you will get in the mean time are .... global events of App.Deactivated and App.Activated. It is possible that completely none of per-page events will fire [but I've not checked - before you do anything I suggest below, CHECK IT].
If this pessimistic view is really true, than in those events, you will have to detect the current theme (->Tim's post), then somehow inform your current Page that themes changed - or not. If you have your ViewModel at least a bit separated from the rest of the app (as it should be:) ) you have an easy option to do it: create in that ViewModel a set of properties (dp or inotif) like Brush Background, Brush Foreground, Brush Hightlight, and other that you need, and instead of harcoding colours in your XAML - bind to those properties. You may event want to create a separate class for all those many Brushes and other Styles, let's say "pub class MyCurrentAppTheme" and keep that props there, and expose such object from ViewModel - whatever. Just Bind your colors to whatever -- but whatever that will be "logically global" and that will be easily accessible from the App.Acticated event handler. Having that done, in the App.Activated, detect the current theme and if changed, so through all the colors kept in VM and set them appropriatelly. Voil'a, whole your App gets recoloured properly.
But mind that still - there might be some transient blinks and flashes between the rendering of cached old theme, refreshing databound objects, and redrawing fresh theme. I hope not, but I sense it may occur, especially when returning from fast-switch tool (long back press): I think that the device captures the 'last screenshot' of your app in the backbuffer and uses that throughout all the time the app is 'minimalized' to do transitions animations, to show the fast-app-switch overview and so on.. again, I've not checked, but I doubt that during such animations the pagecontents are 'live', it could be very demaning on CPU/GPU resources. Any one knows anything on that? It could be a nice test to have some looping animation on the page and then to switch out and check in the fast-switch overview, whether the animation moves or is halted!:)

If your application is tombstoned, all your controls will be recreated and the new theme will be applied. If you'd like to manage your light/dark specific styles in a similar vein to normal themes, you might want to take a look at a custom ResourceDictionary I blogged about a while back.
Unfortunately, as of Mango there, is a bug (?) related to fast application switching that causes the theme to remain unchanged in your application. The bug is outlined in this question and its linked posts:
Is there a bug when changing themes when app is deactivated and reactivated in Windows Phone Mango
My ResourceDictionary is still useful for the initial startup but it appears, unfortunately, that nothing can be done to workaround the Mango bug.

For this no event exists. You need to figure this out manually by comparing the PhoneBackgroundBrush color to see if the user has the dark or light theme and compare it with your last stored value.

Were you able to do some test on the App.Activate - Deactivate?
I decided to use a different path to solve the issue of dynamic theme change.
I've assigned to all text and buttons only system resource colors.
For the icons inside the buttons in the window instead of using PNG images-icons I used the in XAML and assing it a Foreground color from system resource.
For the buttons in the SystemMenuBar there is no issue as they are always on a dark gray background so the black PNG images work just fine.
Hoping this helps.

You can check if the dark theme is in use with this simple check:
public static bool CurrentThemeIsDark
{
get
{
return (Visibility)Application.Current.Resources["PhoneDarkThemeVisibility"] == Visibility.Visible;
}
}

Related

How to get correct background and control colors in property pages?

I'm trying to handle background color properly in a dynamically generated property sheet in dynamically generated property pages in win32 api using MFC (though I expect my question is general, and not restricted to MFC, but since my code and examples use it, it's germane to my question anyway).
So we have a:
CPropertySheet
containing multiple
CPropertyPage
I generate the contents of any given page dynamically - from file resources using a custom dialog definition language - all irrelevant other than to say - a list of controls and their coordinates is created within a given page, and the page is resized to accommodate them. This logic is working beautifully.
However, what doesn't work is that the controls and background of each page draws using the dialog default color/brush.
I've tried a number of ways to attempt to force it to draw using the white color/brush that a hard-coded property sheet / page would.
There are two important pieces to this:
Page Background
Control (on the page) background
For #1, I've tried:
acquire the background brush from parent window class (it's dialog bkgrd) (same is true if I do this and ask the tab control)
change the property page to use WS_EX_TRANSPARENT (PreCreateWindow is not called by the framework when generating a page viz PropertySheet::AddPage)
For #2, I've tried:
overriding OnWndMsg / WM_CTLCOLORSTATIC to forward that request to (A) the parent (sheet), and (B) to the tab control (which is what wants the white in the first place).
However, anytime I use any of the above "ask for the background / forward the request" up the chain to either the sheet or the tab control - I get the dialog background color, never the white I'd expect.
Using Spy64, I can see that for a fully hardcoded property sheet / page - that the only discernable differences I can see is that the dialog window created in AddPage (or its moral equivalent) has WS_CHILD instead of mine which has WS_POPUP (the rest of the styles appear to be the same, such as WS_VISIBLE|DS_3DLOOK|DS_FIXEDSYS|DS_SETFONT|DS_CONTROL and WS_EX_CONTROLPARENT.
So, other than the WS_CHILD, I see no significant differences from what I'm creating and from another property sheet that works properly from a standard resource (i.e. hard coded).
I'm also flummoxed as to how this works normally anyway - since forwarding things like the ctrlcolor message doesn't respond correctly - and asking for the windows background colors similar doesn't - then how is it in a standard case the background colors of controls and pages comes out as white, and not dialog background?
Any ideas or help would be appreciated - I'm kind of running out of ideas...
When Visual Styles were added in Windows XP they really wanted to show off this new feature so they made the tab background a gradient (really a stretched image) instead of a single color and this caused problems in old applications that did custom drawing with the dialog brush as the background.
Because of this, only applications with a comctl32 v6 manifest got the new look but there was a problem; old propertysheet shell extensions would load in new applications (including Explorer) and things would look wrong.
To work around this they also require you (or your UI framework) to call EnableThemeDialogTexture(.., ETDT_ENABLETAB) to get the correct tab page look.
As if things are not tricky enough, there is a undocumented requirement that you also need a button or a static control on the page!
If you have custom controls they have to call DrawThemeParentBackground when you draw if they are partially transparent.
Turns out my old code had defined an ON_WM_ERASEBKGND handler - and removing that (and all of my above attempts) makes it work.
So simply doing NOTHING is the correct answer. D'oh!!!
I'm leaving my shame here in case someone else trips on this! [Whoops!]
(Still interested if anyone has deeper insight into how this mechanism works under the hood)

How to add a NSColorPicker to the application's main window?

I'm building an application to generate an array of colors based on a color chosen by the user.
The default on Mac OS X for color selection is to open a NSColorPanel containing multiple NSColorPickers. But, as the color selection process is the main interaction the user will have with the app, it'd be better to avoid the extra clicks and panel-popping in favor of a more straightforward way.
So, is there any way to add a NSColorPicker object to a window?
I know this is an older question, but check out NSColorWell. From the docs:
NSColorWell is an NSControl for selecting and displaying a single color value.
Interresting Question.
I strongly doubt it (but would love to be proven wrong). NSColorPickers are not NSControls (nor NSCells) so there's no clean wrapper to insert into a window.
Even if you were to instanciate an NSColorPanel and get a reference to its contentView and copy it (with all that defines the color picking controls) to your own window... there's no obvious way of obtaining the color value. NSColorPickers are plug-ins so you can't forsee the controls of a colorPicker.
The only other way I can see (and that's a stretch) would be to manually load the NSColorPickers plug-ins directly. I don't know how successfull this would be.
File a bug report and request the feature?

What could possibily slow down my flex mobile application?

I am working with flex for the last two years on some desktop apps. Until now I never had any performance related issues but today as we completed a mobile application for the iPad, I'm facing a challenge, the application is incredibly slow on the iPad.
http://i.stack.imgur.com/qkbWn.png
Slow, means that when I press a button in the menu to change the splitview I must wait something like 5s. Then scrolling is really slow two, with less than one fps and my TextInput starts to bug (the text is not in his box anymore).
I started to read a lot of blog post and presentation about optimisation for the mobile platform and then I rewrite some of the components I use. I removed the SkinnableContainer for instance and replaced it by a VGroup including some actionScript based drawing.
Now what you see is a VGroup (the dark grey one) containing some others VGroup (the group with title here) and then each widget is an HGroup with a label and a Widget. I only use Label and TextInput for the text.
Creation time is slow even (several seconds to create the view) for another page where there is only 4 text widget on it, or another one with only a list with a custom item renderer where each row is a set of 4 labels.
The whole things is cabled with RobotLegs, with nothing fancy, one models is injected in the view and at the beginning I set a member variable on the view with this object to bind my variables.
Frankly my thinking right now is : it smells fishy because if I've done everything right it is impossible to have such low performance and thinks that flex is competitive on the mobile platform. So right now I'm trying to disable the application piece by piece to try to locate what could slow it like that. I've got a couple suspects to check, for instance I've got some binding warning to check, and then see if robotlegs has got its share of the problem.
So my main question here is what do you think, and could you have some ideas about "is there a problem" and "how do we solve it".
Thanks
Run profiler for startup and separatelly for each operation that takes longed that it needs. Then prioritize the problems and try to solve them with basic optimization techniques.
Some problems you will not be able to solve fast - e.g. time for creating big components. The only option there is to rewrite those components with AS3 without MXML, styles and anything. I'm sure that flash.text.TextField is created many times faster than mx.controls.Label. The same for other components.
When component is created, it can be reused at a very low price. In your app there must be a lot of places where you recreate while you can reuse old components. It will save you memory and time.
Layouts tend to redraw even when it's not needed. If you have a lot of nested layouts, find the most critical places and replace a series of layouts with one custom layout or even component.
This all is very developer time consuming. At the end you will not get a smooth app anyway, but I believe that it can become usable.

Changing UI in reaction to Storyboard.Completed event. Do we need BeginInvoke?

I have a ContentPresenter that switches between 2 states ("editor" and "viewer"). The states have different heights and different values of Content and ContentTemplate properties.
In one state change I resize the control by playing a Storyboard and in reaction to Storyboard.Completed event I change Content/Template properties.
It works basically ok, except I observed occasional flickering. When playing in debugger I observed that modifying above properties in Completed handler may cause strange screen effects (portions of the screen empty, extra shading, lines etc.) that the user observes as flickering.
However, whenever I postponed the ContentPresenter changes by using Dispatcher.BeginInvoke(), the problems seem to disappear. (More testing needed.)
Anyone has an explanation? On the web you'll find numerous code examples that perform UI changes in Storyboard.Completed handler, hence I find it a bit strange.
I suspect it may be more due to timing than needing to be on the UI thread. Try doing a Sleep for a second or so before changing the Content/Template properties instead of using Dispatcher.BeginInvoke(). If the flicker is gone then perhaps trying to change those properties while the Content was busy resizing itself during the storyboard was the culprit - perhaps assigning a fixed size or otherwise disabling the constant resizing during the storyboard would help. That's just a guess though, I'd have to see a sample to really figure it out. If you can make a small sample to reproduce it I'd gladly look at it.

mouse moved events are not detected by NSView

I am trying to make a simple application in which there is a empty red rectangle and whenever the mouse is moved over the upper half border of the rectangle the cursor will become closed hand.
I started with selecting the foundation command line project.Made a transparent NSWindow and embedded a NSView in it with the rectangle, made window to accept mouse moved events(by method: -setAcceptsMouseMovedEvents). I have overridden -canBecomeKeyWindow and -canBecomeMainWindow window to return YES. But somehow none of the -mouseMoved events are being received by NSView.
When I put the same code by making a cocoa application project and creating my window in -applicationDidFinishLaunching method , my view was able to receive -mouseMoved events.
why is it not receiving mouse moved events when I use foundation command line utility project ?
I have also observed that whenever I make a window(carbon or cocoa) through foundation cmd line utility project , the window doesn't become key even on clicking the title bar.On clicking the title bar color remains light grey instead of becoming dark grey. Why is this happening?
I have overridden -canBecomeKeyWindow and -canBecomeMainWindow of NSwindow to return YES.
I would agree with what Joshua has already said. Any application that is going to show a user interface, be it a faceless background process or one which shows up in the Dock, should be in the form of an application bundle, not a plain old Mach-O executable like the Foundation tool template will create.
Also, there are reasons why views do not respond to mouseMoved: events by default:
Mouse moved events can quickly flood the event queue
There is generally little reason to use mouseMoved:, as tracking areas are
far more effective and efficient.
A while back, I wrote a little test app that demonstrates the differences between these 2 approaches:
Moving your mouse around the upper view for roughly 20 seconds results in 1000 events, while in the lower view, which uses tracking areas, less than 50.
Sample GitHub project: https://github.com/NSGod/MouseMoved-vs-TrackingAreas
Again, as Joshua mentioned, it would be helpful if you could describe what you're trying to accomplish. If your app needs to be a background app (LSUIElement == 1), and present an interface without appearing in the Dock, then there are ways to do that (as Josh mentioned, a command-line, non-bundled app is not the way).
You have no event loop to detect events and pass them to your window because your program does not start an NSApplication. See the main.m file of a typical Cocoa application.
It might be helpful to describe what you're trying to accomplish by taking this approach. My guess is you're building a daemon but want a GUI interface to manage the otherwise "headless" daemon. That or you're building a new login management system. In either case, there are specific ways to do both and this isn't it. :-)

Resources