I have recently added Jeff Wilcox's PhoneThemeManager to my app, which works great, although I am having problems changing the application bar buttons to the color I wish to use. My app design specifications require using the Light Theme. The problem I am having is that when the device is already in light theme, upon application loading the appbar foreground is the correct color because the PhoneThemeManager does not overwrite any values, although when in dark theme the appbar foreground values are black (which mimics the default foreground settings in the light theme).
According to his website, "If you have code in your app like “var ab = new ApplicationBar”, beware that that application bar will take on the system’s actual theme colors by default, and not the overridden light/dark coloring that happens with the app.
If you need to new up an ApplicationBar, you should use the convenience method of ThemeManager.CreateApplicationBar() or use the extension method on app bar that I added, MatchOverriddenTheme, to set the color values."
I'm not sure how to implement this to get custom appbar button colors.
I've done the following
public App()
{
// Global handler for uncaught exceptions.
UnhandledException += Application_UnhandledException;
// Standard Silverlight initialization
InitializeComponent();
// Phone-specific initialization
InitializePhoneApplication();
ThemeManager.ToLightTheme();
// Other code that might be here already...
}
And in my MainPage appbar I wish to change the buttons accordingly
private void BuildLocalizedApplicationBar()
{
// Set the page's ApplicationBar to a new instance of ApplicationBar.
ApplicationBar = new ApplicationBar();
ApplicationBar.ForegroundColor = Color.FromArgb(255, 35, 85, 155);
//Not sure where or how to use this?
ApplicationBar.MatchOverriddenTheme(); //to override ThemeManager defaults
//Create appbar buttons
...
}
Any ideas?
Related
I'm trying to made an UWP app that can change of theme. I'm using the instruction RequestedTheme = ElementTheme.Dark;, but this only changes the "basic items", I'm talking about the background and text.
The textBox, the ContentDialog and others aren't into the dark mode.
I'd like to find a way to "dark" ALL the items into the app, not only the text and background.
Hope there's any way.
You can set theme on the application and element level.
If you want to set it on application level, it must be done when the app is started (in App.xaml.cs constructor). This setting cannot be changed at runtime.
To switch theme at runtime, you can utilize the RequestedTheme property on a control. This applies the theme to the control and its children in the visual hierarchy. This can be switched any time at runtime. To make the selected theme apply to the whole application, you need to set it on a top-level visual element - ideally the root element of the window:
var root = (FrameworkElement)Window.Current.Content;
root.RequestedTheme = ElementTheme.Dark;
Usually, the window's content is a Frame but, more generally it can be an arbitrary FrameworkElement.
I have a inherited Listview which standard has to be in Tile Mode. When using this control, the DrawItem gives e.bounds which are clearly bounds of largeIcon view ?? When debugging to check the view it is actually set to, it says it's in Tile view ?? Yet e.DrawText draws LargeIcon view ??
......... Edit: .................
This seems only to happen when the control is placed upon another usercontrol?
......... Edit 2: .................
It gets stranger ... When i add buttons next to the list to change the view at runtime, "Tile" is the same as "LargeIcon", and "List" view is the same as "SmallIcons" ??? I've also completely removed the ownerdraw ...
.......... Edit 3: .................
MSDN Documentation:
Tile view
Each item appears as a full-sized icon
with the item label and subitem
information to the right of it. The
subitem information that appears is
specified by the application. This
view is available only on Windows XP
and the Windows Server 2003 family.
On earlier operating systems, this value is ignored and the ListView
control displays in the LargeIcon
view.
Well I am on XP ?!?
...... Edit 4 .....................
Holy mother of strangeness ...
We are now at the point we've completely stripped down EVERYTING ... We have a standard listview on a form, manually filled with 3 values. No Ownerdraw. It is set to Tile.
When we start this form, the list is drawn as LARGEICON.
Now, we start another blank solution, copy this exact same form to the new project, start debug and low and behold .. it is drawn in TILE view ????
... help ...
public class InheritedListView : ListView
{
//Hiding members ... mwuahahahahaha //yeah i was still laughing then
[BrowsableAttribute(false)]
public new View View
{
get { return base.View; }
}
public InheritedListView()
{
base.View = View.Tile;
this.OwnerDraw = true;
base.DrawItem += new DrawListViewItemEventHandler(DualLineGrid_DrawItem);
}
void DualLineGrid_DrawItem(object sender, DrawListViewItemEventArgs e)
{
View v = this.View;
//**when debugging, v is Tile, however e.DrawText() draws in LargeIcon mode,
// e.Bounds also reflects LargeIcon mode ???? **
}
................................
This code behaves differently at different solutions:
private void InitializeComponent()
{
System.Windows.Forms.ListViewItem listViewItem1 = new System.Windows.Forms.ListViewItem("fhsdhdsfhsdfhs");
System.Windows.Forms.ListViewItem listViewItem2 = new System.Windows.Forms.ListViewItem("fdshdsfhdsfhsd");
System.Windows.Forms.ListViewItem listViewItem3 = new System.Windows.Forms.ListViewItem("hdshsdfhsdfhsdfsdfsdf");
this.listView1 = new System.Windows.Forms.ListView();
this.SuspendLayout();
//
// listView1
//
this.listView1.Items.AddRange(new System.Windows.Forms.ListViewItem[] {
listViewItem1,
listViewItem2,
listViewItem3});
this.listView1.Location = new System.Drawing.Point(36, 12);
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(487, 242);
this.listView1.TabIndex = 2;
this.listView1.TileSize = new System.Drawing.Size(480, 50);
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.View = System.Windows.Forms.View.Tile;
//
// TestControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(595, 712);
this.Controls.Add(this.listView1);
this.Name = "TestControl";
this.Text = "TestControl";
this.ResumeLayout(false);
}
#endregion
OK, we found it. The magic spell is:
Application.EnableVisualStyles();
We skipped this line of code to test our form.
If you don't call this method before you create your form with your listview, TILE view gets drawn as LARGEICON.
Seems totally logical ... :-(
http://blogs.msdn.com/rprabhu/archive/2003/09/28/56540.aspx
Q What does Application.EnableVisualStyles actually do?
Windows XP ships with two versions of the Common Controls Library (comctl32.dll) - versions 5.8 and 6.0. v5.8 renders controls in the "Classic" style that you get on Windows NT/2000 and Windows 9x. v6.0 renders controls using the XP Visual Styles look and feel. Since most Windows Forms controls are based on comctl32, how they are rendered depends on which version of comctl32 is used to do the rendering. By default, v5.8 is used to render the client area of the app and v6.0 is used to render the non-client area. That is why you see the title bar and window borders automatically render "themed", while the controls (like Button, TextBox, ListView, ComboBox and so on) have the classic look by default.
In v1.0 of the Framework, the way to get visual styles in a Windows Forms app was to ship a manifest file with the app, that has information in it to indicate that v6.0 of comctl32 should be used for rendering. While this works fine, many developers felt it cumbersome to author, maintain and deploy manifest files. They felt the need to be able to do this programmatically. Now, the Platform SDK does provide API to do this. Basically, you need to create and activate an Activation Context that has pretty much the same DLL redirection information in it as the manifest file. The Activation Context API can be used to do this in a way suitable to your application.
If you take a look at these API, you will probably notice that they aren't very easy to use. While the advanced developers may like to tinker around with activation contexts, it is probably not something a developer who wants some "quick and dirty" code to get visual styles will do. So the Windows Forms team decided to wrap these API and expose a simple method that developers could call, that would isolate them from these complexities. So, essentially, when you call Application.EnableVisualStyles, we set up an activation context around the application's message loop, so that comctl32 function calls can be properly redirected to comctl32 v6.0. That way, you don't need to include a manifest with your app.
I'm trying to create an application that would use multiple windows. For starters I'd like it to have a splash screen window and a "main window". I came along this article: http://southworks.com/blog/2010/01/26/creating-a-multi-shell-application-in-prism-v2/ however it doesn't seem to suit my needs. Author is creating 2 windows at the same time, also showing both right from the start. What I want to do is to create this splash screen window (with some nice loading indicators) and only when it's underlying logic will complete its tasks, I want to show another window
protected override DependencyObject CreateShell() {
//return Container.Resolve<MainShell>();
return Container.Resolve<SplashScreenShell>();
}
protected override void InitializeShell() {
base.InitializeShell();
App.Current.MainWindow = (Window)Shell;
App.Current.MainWindow.Show();
}
Another issue is that when I use this code, all my modules (so even those used only by MainShell) are getting loaded and initialized, and that's totally not what I want. Mainly because Prism looks for RegionName that is not present on SplashScreenShell (but is present on the second shell).
I'm using Prism 6.1.0 and .NET 4.6.
Why not just show your splash screen before you call MainWindow.Show? Just show it as ShowDialog to stop the bootstrapper form continuing to process until you close your splash screen.
protected override void InitializeShell()
{
var sc = new SplashScreen();
sc.ShowDialog();
App.Current.MainWindow = (Window)Shell;
App.Current.MainWindow.Show();
}
The good patern is to stick to one window for the whole application. My proposal is to create splash screen as UserControl and then kind of mess around with visibility.
Your MainView may be looking as follows
<Grid>
<ContentControl Content="{Binding CurrentViewModel}"/>
<userControl:SplashScreen/>
</Grid>
At this point your splash screen covers view and once the view is loaded you make the SplashScreen invisible. In order to do so create another class which will expose boolean property like IsVisible, and method Show/Hide for making splash screen visible and invisible respectively. Subsequently, you set SplashScreen's DataContext to that class, bind Visibility property to IsVisible and make use of BooleanToVisibilityConverter, provided by WPF by default. For appearance sake, you can set splash sreen opacity to, for instance 0.75, so that it would show through splash screen displaying some destination view simultaneously.
Whenever you want to show splash screen you invoke Show method, within method you set IsVisible to true, PropertyChanged event is raised and changes are reflected at view. As a result Visibility is set to true and Splash screen shows up on the top covering everything else.
If you follow these steps you should acquire similar outcome. Message being displayed can be explicitly adjusted as well, as a replacement for hardcoded "Loading".
I have a page in a Windows Phone 8.1 app where I have a few components that should be able to have three different color states. They should either be red, blue or the current theme's foreground color.
Therefore, if my app is started using the Dark theme on the phone, and then the user steps out of the app and changes the Light theme, and steps in to my app again, I need to immediately change components that had the old theme's foreground color.
Since the components are supposed to change between different colors (where the theme's foreground color is just one of them) I can't set their Foreground to PhoneForegroundColor in XAML.
What I've done is to add a Resuming event listener that does this:
myTextBlock.Foreground = new SolidColorBrush((Color)Application.Current.Resources["PhoneForegroundColor"]);
But... the Resuming event is fired before the resources of Application.Current are updated, so I end up with the same color as before. If the user steps out again and in again, it'll work since Application.Current.Resources["PhoneForegroundColor"] was updated at some point after the Resuming event the previous time.
Question: When can I first read the updated Application.Current.Resources["PhoneForegroundColor"], since Resuming doesn't seem to be the right place?
Question: Alternatively, is there a way for myTextBlock to inherit another component's ForegroundColor (CSS-ish), so that I can change the myTextBlock.Foreground programatically between Red/Blue/Inherit without having to mind changes to the Phone Theme within my app's lifecycle?
Any suggestions appreciated!
Regarding your first question: The "Resume process" isn't officially documented, but I figured out the following:
Resume gets called on the UI thread. As it is a void returning method, the caller will just continue, when it has an await inside. If you marshall something into the UI thread, it will be in the dispatcher queue and therefor run after the current task (resume).
So I just made this (and it works^^):
private async void App_Resuming(object sender, object e)
{
var x1 = new SolidColorBrush((Color)Application.Current.Resources["PhoneForegroundColor"]);
Debug.WriteLine(x1?.Color.ToString());
// Await marshalls back to the ui thread,
// so it gets put into the dispatcher queue
// and is run after the resuming has finished.
await Task.Delay(1);
var x2 = new SolidColorBrush((Color)Application.Current.Resources["PhoneForegroundColor"]);
Debug.WriteLine(x2?.Color.ToString());
}
Regarding your second question: You could introduce a "ValueProvider" in your app.xaml, that registers for the resume event and just provides a dependency property with the current color.
You will still have to set that on any TextBlock you want to use that in, but at least directly in XAML. This might work for styles too, but did not try that.
Sample implementation....
Provider:
public class ColorBindingProvider : DependencyObject
{
public ColorBindingProvider()
{
App.Current.Resuming += App_Resuming;
}
private async void App_Resuming(object sender, object e)
{
// Delay 1ms (see answer to your first question)
await Task.Delay(1);
TextColor = new SolidColorBrush((Color)Application.Current.Resources["PhoneForegroundColor"]);
}
public Brush TextColor
{
get { return (Brush)GetValue(TextColorProperty); }
set { SetValue(TextColorProperty, value); }
}
public static readonly DependencyProperty TextColorProperty =
DependencyProperty.Register("TextColor", typeof(Brush), typeof(ColorBindingProvider), new PropertyMetadata(null));
}
App.xaml:
<Application.Resources>
<local:ColorBindingProvider x:Name="ColorBindingProvider" TextColor="{StaticResource PhoneForegroundBrush}" />
</Application.Resources>
MainPage.xaml:
<TextBlock Text="Hey ho let's go" Foreground="{Binding TextColor, Source={StaticResource ColorBindingProvider}}" />
In Windows Phone 8.1 you are able to determine the selected theme via Application.Current.RequestedTheme witch will return a value of the enum Windows.UI.Xaml.ApplicationTheme.
example:
public static string GetImagePath(){
// if the background color is black, i want a white image
if(Application.Current.RequestedTheme == ApplicationTheme.Dark)
return "ms-appx:///Assets/img_light.jpg";
// if the background color is white, i want a dark image
return "ms-appx:///Assets/img_dark.jpg";
}
side note: you are even able to change the selected theme with Application.Current.RequestedTheme
more details: https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.application.requestedtheme
Register to App_Resuming didn't work for me because this event isn't raised when application is not suspended. I had to listen to Window.Current.CoreWindow.VisibilityChanged += CoreWindow_VisibilityChanged;
No need for Task.Delay with this solution.
In my application the user can choose what colour they would like a particular feature of the app to be.
They can choose from a variety of colours which works fine, however when trying to set the Grid's background to the accent colours; when chosen, a NullReferenceException was unhandled error appears.
The code I am using is:
Color accentColour = (Color)Application.Current.Resources["PhoneAccentColor"];
gridColour.Background = new SolidColorBrush(accentColour);
Anyone know what I am doing wrong? (I've also tried using a Rectangle and it's .Fill property).
Thanks.
[SOLVED: Post solved in comments.]
You can try that code in OnNavigatedTo Event. Its Working.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
Color accentColour = (Color)Application.Current.Resources["PhoneAccentColor"];
ContentPanel.Background = new SolidColorBrush(accentColour);
}
I guess you can easily do this by binding the PhoneAccent color within your XAML for your Grid.
These threads would be helpful:
Windows Phone 8 Change Accent and Theme Colour
windows phone 8 xaml set the color of a button on click
Hope it helps!