changing xamarin.forms colors at runtime - c#

i am making an app using xamarin.forms and i have set up a color scheme that i want to be able to change within the settings to either a dark style or a light style right now it all works except i have to restart the app everytime after i select a different color scheme.
here is where i am trying to change it at runtime
private void DarkThemeClick(object sender, EventArgs e)
{
database.DropTable(new StyleModel());
database.CreateTable(new StyleModel());
database.SaveItem(new StyleModel() { ThemeNum = 1 });
App.ActiveStyle = new DarkStyle();
}
private void LightThemeClick(object sender, EventArgs e)
{
database.DropTable(new StyleModel());
database.CreateTable(new StyleModel());
database.SaveItem(new StyleModel() { ThemeNum = 0 });
App.ActiveStyle = new LightStyle();
}
here is an example of an item that im using that i want to change the colors on
using System;
using TestXamForms.Style;
using Xamarin.Forms;
namespace TestXamForms.Helpers
{
class EntryValueCell : StackLayout
{
public EntryValueCell(string key,int FieldIdx, string value = "", bool isNumber = false)
{
Entry entry;
Label label = new Label()
{
TextColor = App.ActiveStyle.LabelTextColor,
Text = key,
HorizontalOptions = LayoutOptions.End
};
if (isNumber)
{
entry = new Entry()
{
ClassId = FieldIdx.ToString(),
TextColor = App.ActiveStyle.LabelTextColor,
HorizontalOptions = LayoutOptions.FillAndExpand,
Keyboard = Keyboard.Numeric,
Text = value,
};
}
else
{
entry = new Entry()
{
ClassId = FieldIdx.ToString(),
TextColor = App.ActiveStyle.LabelTextColor,
HorizontalOptions = LayoutOptions.FillAndExpand,
Keyboard = Keyboard.Text,
Text = value
};
}
BackgroundColor = App.ActiveStyle.StackLayoutBackground;
Orientation = StackOrientation.Horizontal;
VerticalOptions = LayoutOptions.FillAndExpand;
Children.Add(label);
Children.Add(entry);
}
}
}
here is an example of one of the color schemes
using Xamarin.Forms;
namespace TestXamForms.Style
{
public class LightStyle : StyleBase
{
public LightStyle()
{
LabelTextColor = Color.Black;
ButtonColor = Color.FromHex("337ab7");
StackLayoutBackground = Color.FromHex("eff0f1");
InputBackgroundColor = Color.White;
PlaceHolderColor = Color.Gray;
TableColor = Color.FromHex("e6e6e6");
StacklayoutBorderColor = Color.Black;
}
}
}
here is styleBase that the file above is inheriting
using TestXamForms.Models;
using Xamarin.Forms;
namespace TestXamForms.Style
{
public class StyleBase : ModelBase
{
public enum ThemeNum : int
{
Light = 0, Dark = 1
}
public Color LabelTextColor { get; set; }
public Color ButtonColor { get; set; }
public Color StackLayoutBackground { get; set; }
public Color InputBackgroundColor { get; set; }
public Color PlaceHolderColor { get; set; }
public Color StacklayoutBorderColor { get; set; }
public Color TableColor { get; set; }
public int ThemeNums { get; set; }
}
}
here is the part of App.cs file that loads the color scheme when the app starts
static StyleBase activeStyle { get; set; }
public static StyleBase ActiveStyle
{
get
{
if (activeStyle == null)
{
StyleModel styleBase = database.GetItems(new StyleModel()).First();
if (styleBase == null)
{
database.SaveItem(new StyleModel() { ThemeNum = 0 }); //sets the default color scheme to light style
styleBase = database.GetItems(new StyleModel()).First();
}
int themeNum = styleBase.ThemeNum;
switch (themeNum)
{
case (int)StyleBase.ThemeNum.Dark:
activeStyle = new DarkStyle();
break;
case (int)StyleBase.ThemeNum.Light:
activeStyle = new LightStyle();
break;
}
}
return activeStyle;
}
set { } }

Have a look at this blog post. Particularly the bit about DynamicResources and Styles.
<Application
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Your.App">
<Application.Resources>
<ResourceDictionary>
<Color x:Key="backgroundColor">#33302E</Color>
<Color x:Key="textColor">White</Color>
</ResourceDictionary>
</Application.Resources>
</Application>
Now set your resources
<Label Text="{Binding Name}" FontSize="Medium" FontAttributes = "Bold" TextColor = "{DynamicResource textColor}" LineBreakMode="NoWrap"/>
<Label Text="{Binding Text}" FontSize="Small" LineBreakMode="WordWrap" TextColor = "{DynamicResource textColor}"/>
Now in code you can change your resource on the fly
App.Current.Resources ["backgroundColor"] = Color.White;
App.Current.Resources ["textColor"] = Color.Black;
If you're using 2.3 you could also try the built in themes

The problem you are facing is that everything is already rendered and you have not bound to any property which will re render the changes you made in the code to the UI. You can take the MVVM approach and create properties and bind to them and notify when they are changed in the UI thread.
If you are interested only in dark and light themes then you can use the in built Light Theme and Dark Theme. You can also create Custom Themes.
A theme is added to a Xamarin.Forms application by including the
Xamarin.Forms.Theme.Base Nuget package, plus an additional package
that defines a specific theme (eg. Xamarin.Forms.Theme.Light) or else
a local theme can be defined for the application.
In addition to automatically styling the common controls the Light and Dark themes currently support the following classes that can be applied by setting the StyleClass on these controls:
BoxView -
HorizontalRule,
Circle,
Rounded
Image -
Circle,
Rounded,
Thumbnail
Button -
Default,
Primary,
Success,
Info,
Warning,
Danger,
Link,
Small,
Large
Label -
Header,
Subheader,
Body,
Link,
Inverse
To add a theme to your application, do the following :
Add the Nuget packages to your project.
Add theme to Resource Dictionary in App.xaml
Use the Style class to apply predefined style classes in the theme.
<Button Text="Button Class Default" StyleClass="Default" />
<Button Text="Button Class Primary" StyleClass="Primary" />
<Button Text="Button Class Success" StyleClass="Success" />
Read more about themes here.

Related

How to rotate Grid depending on a property easiest way

Hi I would like to know what the easies way to rotate a Grid would be.
I have 4 pages:
private static Figure[] array;
public App ()
{
Initialize(array); // Fills array with figures with ImageSources
InitializeComponent ();
MainPage = new Page(array,Color.Red);
}
class Figure
{
private ImageSource Source {get; set;}
public Figure(ImageSource source)
{
Source = source;
}
}
class Page
{
private Color Color;
private Grid Grid;
public Page (Figure[] Figures, Color color)
{
Color = color;
// Now this is where I need help...
}
}
I would like to have a Grid always the same size and always filled with the same array but depending on the Color the orientation should change. In fact the whole Grid should just rotate 90degrees depending on the Color. These Grids should have ImageButtons which bind to the Imagesource of the figure (with a Converter). I thought about Creating 4Grids in Xaml and implement everything by hand and just give every page the custom Grid. Another option I came up with was creating one Grid only and using the rotation-method of the Grid (but with this option I have to rotate back every child of the Grid as otherwise the pictures would rotate with the Grid... As I think both solutions are quite inconvenient I was wondering what other options I have. Maybe someone can help me? Thanks a lot...
Example of ImageSources that change based on a setting.
XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TestBugs.MainPage">
<StackLayout>
<Label Text="Test"/>
<Grid ColumnDefinitions="50,50" RowDefinitions="50,50">
<Image Grid.Row="0" Grid.Column="0" Source="{Binding Source1A}" BackgroundColor="Red"/>
<Image Grid.Row="0" Grid.Column="1" Source="{Binding Source1B}" BackgroundColor="Green"/>
<Image Grid.Row="1" Grid.Column="0" Source="{Binding Source2A}" BackgroundColor="Blue"/>
<Image Grid.Row="1" Grid.Column="1" Source="{Binding Source2B}" BackgroundColor="Yellow"/>
</Grid>
</StackLayout>
</ContentPage>
C#:
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace TestBugs
{
public partial class MainPage : ContentPage
{
// REPLACE "TestBugs" with your project's assembly name.
public const string AssemblyName = "TestBugs";
public enum Orientation
{
One, Two, Three, Four
}
const int NOrientations = 4;
public MainPage()
{
// Assuming stored locally in files or resources.
// If need server queries, recommend not doing this in constructor.
LoadOurImages();
InitializeComponent();
// In this simple example, the binding sources are in the page itself.
BindingContext = this;
}
protected override void OnAppearing()
{
base.OnAppearing();
BackgroundTestLoop();
}
static Random Rand = new Random();
private void BackgroundTestLoop()
{
Task.Run(async () =>
{
const int NTimes = 20;
for (int i = 0; i < NTimes; i++)
{
await Task.Delay(3000);
Orientation nextOrient = (Orientation)Rand.Next(NOrientations);
// Only affect UI from main thread.
Device.BeginInvokeOnMainThread(() =>
{
Orient = nextOrient;
});
}
});
}
public Orientation Orient {
get => _orient;
set
{
_orient = value;
// When Orient changes, that affects the values of these properties.
// OnPropertyChanged is from super-class BindableObject.
OnPropertyChanged(nameof(Source1A));
OnPropertyChanged(nameof(Source1B));
OnPropertyChanged(nameof(Source2A));
OnPropertyChanged(nameof(Source2B));
}
}
private Orientation _orient = Orientation.One;
// Public getters. These change when Orient changes.
public ImageSource Source1A => Sources[Indexes1A[(int)Orient]];
public ImageSource Source1B => Sources[Indexes1B[(int)Orient]];
public ImageSource Source2A => Sources[Indexes2A[(int)Orient]];
public ImageSource Source2B => Sources[Indexes2B[(int)Orient]];
List<string> ResourcePaths = new List<string> {
"apple.png", "banana.png", "car.png", "dog.png"};
List<ImageSource> Sources = new List<ImageSource>();
// Change these as needed.
List<int> Indexes1A = new List<int> { 0, 1, 2, 3 };
List<int> Indexes1B = new List<int> { 1, 2, 3, 0 };
List<int> Indexes2A = new List<int> { 2, 3, 0, 1 };
List<int> Indexes2B = new List<int> { 3, 0, 1, 2 };
private void LoadOurImages()
{
foreach (var path in ResourcePaths)
Sources.Add(CreateOurSource(path));
}
private ImageSource CreateOurSource(string resourcePath)
{
// For embedded resources stored in project folder "Media".
var resourceID = $"{AssemblyName}.Media.{resourcePath}";
// Our media is in the cross-platform assembly. Find that from this page.
Assembly assembly = this.GetType().GetTypeInfo().Assembly;
ImageSource source = ImageSource.FromResource(resourceID, assembly);
return source;
}
}
}

C# Xaml - Use Custom Class - Works programatically but not in Xaml

I'm pretty new with Xaml and i'm facing an issue . I want to use FontAwesome Icons in my app and after following a tutorial , i can use the icons programmatically (Code Below) .
Content = new StackLayout
{
Children = {
new FontIcon(FontIcon.Icon.Globe) {TextColor=Color.Red }
},
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
However , when i try to implement this in Xaml - it crashes my app.
Code for Shared class extending label :
using Xamarin.Forms;
namespace myApp.Fonts
{
public class FontIcon : Label
{
public const string Typeface = "FontAwesome";
public FontIcon(string faIcon = null)
{
FontFamily = Typeface;
Text = faIcon;
}
public static class Icon
{
public static readonly string Gear = "";
public static readonly string Globe = "\uf000";
}
}
}
Xaml code ...Note that i'm already using the xmlns:local for another class
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="myApp.TestPage"
xmlns:ctt="clr-namespace:myApp.Fonts">
<ctt:FontIcon FontIcon ="\uf000" VerticalOptions="Center" HorizontalOptions="Center" />
I'm guessing the issue is with this line :
<ctt:FontIcon FontIcon ="\uf000" VerticalOptions="Center" HorizontalOptions="Center" />
I'm not sure how to access that class via xaml or if its even possible to use xlmns:ctt
EDIT-------------------------------------------------------------------------
I used debug and this is the actual error :
System.MissingMethodException: Default constructor not found for type myApp.Fonts.FontIcon
Edit 2 :
I did this :
public FAIcon()
{
}
And in xaml :
<custom:FAIcon FontFamily = "Typeface" Text = "\uf000" VerticalOptions="Center" HorizontalOptions="Center" />
The app doesn't crash now but it displays the plain text instead of the icon
This is my android renderer :
[assembly: ExportRenderer(typeof(FontIcon), typeof(FARenderer))]
namespace myApp.Droid.Renderers
{
public class FARenderer : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
Control.Typeface = Typeface.CreateFromAsset(Forms.Context.Assets, FontIcon.Typeface + ".ttf");
}
}
}
}
if you always want to use FontAwesome, set it in your constructor:
public const string Typeface = "FontAwesome";
public FAIcon()
{
FontFamily = TypeFace;
}
don't do this in your XAML, it just sets the FontFamily to "TypeFace" which is not what you want
<custom:FAIcon FontFamily = "Typeface" ...

passing font size to user control tool tip in Winform C# project

Question: I have a Winform C# project that changes the tool tip text of a user control tool tip when passed from a host project. I need to pass font size as a variable, but dont know where to make the changes. I have tried a plethora of solutions online and am stuck with this implementation. Any help in this direction will be really appreciated.
What I have so far:
I have a C# user Control project where i have set a property to set the tool tip text to change to user specified value in my UC_ToolTipButton project, where the contents of the project are as below:
UC_ToolTipButton.cs
using System.Windows.Forms;
namespace UC_ToolTipButton
{
public partial class UC_ToolTipButton : UserControl
{
public string TT_Message
{
get{
return ToolTip_Message.GetToolTip(btnTT);
}
set{
ToolTip_Message.SetToolTip(btnTT, value);
}
}
public UC_ToolTipButton()
{
InitializeComponent();
}
}
}
In my designer file, I have placed a button (btnTT) on which I have put a tool tip (ToolTip_Message).
When I compile this User Control Forms project, it works fine and creates a dll file.
Upon importing this file in a project TryButtonTooltip, where I have the file TryTooltipForm.cs with the following content
using System.Windows.Forms;
namespace TryButtonToolTip
{
public partial class TryToolTipForm : Form
{
public TryToolTipForm()
{
InitializeComponent();
uC_TTMessage.TT_Message = #"Hi";
}
}
}
Set OwnerDraw on ToolTip to true, in ToolTip's Draw event set the desired font, then in Popup event measure and set the size of your ToolTip, as is explained in the example here.
For example like this (untested):
public partial class UC_ToolTipButton : UserControl
{
public string TT_FontFamily { get; set; }
public float TT_FontSize { get; set; }
public string TT_Message
{
get
{
return ToolTip_Message.GetToolTip(btnTT);
}
set
{
ToolTip_Message.SetToolTip(btnTT, value);
}
}
public UC_ToolTipButton()
{
InitializeComponent();
TT_FontFamily = "Tahoma";
TT_FontSize = 10;
ToolTip_Message.OwnerDraw = true;
ToolTip_Message.Draw += new DrawToolTipEventHandler(TT_Draw);
ToolTip_Message.Popup += new PopupEventHandler(TT_Popup);
}
private void TT_Popup(object sender, PopupEventArgs e)
{
using (Font f = new Font(TT_FontFamily, TT_FontSize))
{
e.ToolTipSize = TextRenderer.MeasureText(ToolTip_Message.GetToolTip(e.AssociatedControl), f);
}
}
private void TT_Draw(System.Object sender,
System.Windows.Forms.DrawToolTipEventArgs e)
{
e.DrawBackground();
e.DrawBorder();
using (StringFormat sf = new StringFormat())
{
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
using (Font f = new Font(TT_FontFamily, TT_FontSize))
{
e.Graphics.DrawString(e.ToolTipText, f, SystemBrushes.ActiveCaptionText, e.Bounds, sf);
}
}
}
}

Xamarin forms change background color of navigation bar

I'm using Xamarin.Forms and trying to change the background color of the navigation bar on iOS.
I have a customized navigation bar class that inherits from NavigationPage, with a bindable property and constructor, which sets the color of the navigation bar. According to my understanding the navigation bar has a default background (black) on top of it Xamarin.Forms navigation background. I'm able to set the background color with the SetColor() method (see below). However, it leaves a black line, which is the background of the navigation bar (iOS) as shown in the pic. Picture Link
Now, I'm trying to set the iOS navigation bar background color to white or transparent. Ive spent a lot of time but nothing worked. Could someone assist how to set the background to white.
//PCL class
public class CustomNavigationalPage : NavigationPage
{
public static readonly BindableProperty BarBgColorProperty =
BindableProperty.
Create<CustomNavigationalPage, UIColor>
(p => p.BarBackgroundColorR, null);
public UIColor BarBackgroundColorR
{
get { return (UIColor)base.GetValue (BarBgColorProperty); }
set { base.SetValue (BarBgColorProperty, value); }
}
public NavigationalPageCustomized() : base()
{
SetColor();
}
void SetColor()
{
BarBackgroundColor = Color.Transparent;
BarTextColor = Color.Blue;
}
}
Navigation bar renderer class:
[assembly: ExportRenderer (typeof (CustomNavigationalPage), typeof (CustomNavigationPageRenderer))]
namespace project.iOS
{
public class CustomNavigationPageRenderer : NavigationRenderer
{
public CustomNavigationPageRenderer()
{
// UINavigationBar.Appearance.SetBackgroundImage (UIImage.FromFile ("navbg.png"), UIBarMetrics.Default);
}
protected override void OnElementChanged (VisualElementChangedEventArgs args)
{
base.OnElementChanged (args);
var nb = (NavigationalPageCustomized) Element;
if (nb != null)
{
nb.BarBackgroundColorR = UIColor.White;
}
}
}
}
Try this code in your PCL of Xamarin.forms. Change below code in the
constructor of App.xaml.cs.
public App()
{
MainPage = new NavigationPage(new Page1())
{
BarBackgroundColor = Color.Gray
};
}
You can set this in your global App.xaml file
<Style TargetType="NavigationPage">
<Setter Property="BarBackgroundColor" Value="Blue"/>
<Setter Property="BarTextColor" Value="White"/>
</Style>
Change to your own colors
Try the following code. Good Luck
[assembly: ExportRenderer (typeof (CustomNavigationalPage), typeof (CustomNavigationPageRenderer))]
namespace project.iOS
{
public class CustomNavigationPageRenderer : NavigationRenderer
{
public CustomNavigationPageRenderer()
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
//Background image
this.NavigationBar.BarTintColor = UIColor.FromPatternImage (UIImage.FromFile ("AnyResourceImage.png"));
//Your desire color
this.NavigationBar.BarTintColor = UIColor.Red;
//Right item color
this.NavigationBar.TopItem.RightBarButtonItem.TintColor = UIColor.FromPatternImage (UIImage.FromFile ("AnyResourceImage.png"));
//Left item color
this.NavigationBar.TopItem.LeftBarButtonItem.TintColor = UIColor.Black;
}
}
}
//Note : Please remove any background color you set in forms shared or pcl project. Hint in this class > CustomNavigationalPage
This used to require a custom renderer, but no longer does in XF 1.3. NavigationPage now has BarBackgroundColor and BarTextColor properties, which seem to work well. Unfortunately, there is no ability to change the font though without a custom renderer (that I have found).
For me this worked beautifully:
(App.Current.MainPage as NavigationPage).BarBackgroundColor = Color.FromHex("#4388CC");
I've puted this code in the constructor of the page's ViewModel.
Hope this works for you too.
NavigationController.NavigationBar.TitleTextAttributes = new UIStringAttributes() { ForegroundColor = UIColor.White };

Unable to display piechart on pivot screen (amchart-quickchart)

I'm using amCharts-Quick-Charts to display piechart data but I cannot make it display on a pivot screen. The whole screen is just blank when I execute the program, is anyone able to help?
XAML code
<phone:PivotItem Header="Pie Chart">
<Grid>
<amq:PieChart x:Name="pie1"
TitleMemberPath="title"
ValueMemberPath="value"
>
</amq:PieChart>
</Grid>
</phone:PivotItem>
XAML.CS
namespace Project
{
public partial class Humidity : PhoneApplicationPage
{
public Humidity()
{
InitializeComponent();
}
public ObservableCollection<PData> Data = new ObservableCollection<PData>()
{
new PData() { title = "slice #1", value = 30 },
new PData() { title = "slice #2", value = 60 },
new PData() { title = "slice #3", value = 40 },
new PData() { title = "slice #4", value = 10 },
};
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
pie1.DataSource = Data;
}
}
public class PData
{
public string title { get; set; }
public double value { get; set; }
}
}
Looks like you copied the code from AmCharts-in-Windows-Phone? The project and code works just fine. My guess is you pasted the code incorrectly.
Put a break point at
pie1.DataSource = Data; // put a break point here
Does it break at that line?
If NO then you need to hook up the PhoneApplicationPage_Loaded by clicking on the event icon in the designer and setting the Loaded event to that specific function.
If YES then make sure nothing is covering and overriding the Chart inside your XAML.
Pivot Page example
<Grid x:Name="LayoutRoot">
<phone:Pivot>
<phone:PivotItem Header="one">
<amq:PieChart x:Name="pie1"
TitleMemberPath="title"
ValueMemberPath="value">
</amq:PieChart>
</phone:PivotItem>
<phone:PivotItem Header="two"></phone:PivotItem>
<phone:PivotItem Header="three"></phone:PivotItem>
</phone:Pivot>
</Grid>
If all is good it should look like this

Categories

Resources