I have a class that inherits from TextBox
public class DecimalTextBox : TextBox
{
#region Float Color
public static readonly DependencyProperty FloatColorProperty = DependencyProperty.Register("FloatColor", typeof(Color), typeof(DecimalTextBox), new FrameworkPropertyMetadata(Colors.Red));
public Color FloatColor
{
get { return (Color)GetValue(FloatColorProperty); }
set { SetValue(FloatColorProperty, value); }
}
#endregion
. . . . .. OTHER STUFF
}
I want to style this control using something like this:
<Style x:Key="DecimalTextBoxGridStyle" TargetType="DecimalTextBox">
<Setter Property="TextAlignment" Value="Right"/>
<Setter Property="FloatColor" Value="Black"/>
<Setter Property="BorderBrush" Value="Transparent"/>
</Style>
But it style told me
DecimalTexbox type isn't admited in wpf project
How can I do to that ?
There is another approach ?
Include the XAML namespace:
<Style x:Key="DecimalTextBoxGridStyle" TargetType="local:DecimalTextBox">
where local is mapped to the CLR namespace in which the DecimalTextBox class is defined:
<Window ...
xmlns:local="clr-namespace:WpfApplication1"
Related
I have a Xamarin app which defines certain attributes and styles for the controls centrally in the App.xaml
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="AppMsMovil.App">
<Application.Resources>
<ResourceDictionary>
<Color x:Key="MainColorBlue">#003E62</Color>
<Color x:Key="MainTextColorBlue">White</Color>
<Color x:Key="SecondaryColorBlue">#6f95ab</Color>
<Color x:Key="MainColorRed">#EC1B30</Color>
<Color x:Key="MainTextColorRed">White</Color>
<Color x:Key="SecondaryColorRed">#edb2b8</Color>
<Color x:Key="MainColorGray">#e6e4df</Color>
<Color x:Key="SelectedItemColor">#f7d6a1</Color>
<Color x:Key="UnselectedItemColor">White</Color>
<Color x:Key="CanceledColor">#ffa099</Color>
<Color x:Key="ClosedColor">#fded98</Color>
<Color x:Key="SentColor">#a9efbb</Color>
<Style TargetType="Entry">
<Setter Property="BackgroundColor" Value="White" />
<Setter Property="PlaceholderColor" Value="Gray" />
<Setter Property="TextColor" Value="Black" />
</Style>
<Style TargetType="Button">
<Setter Property="BackgroundColor" Value="{StaticResource MainColorBlue}" />
<Setter Property="TextColor" Value="White" />
<Setter Property="CornerRadius" Value="20" />
</Style>
<Style TargetType="Label">
<Setter Property="TextColor" Value="{StaticResource MainColorBlue}" />
</Style>
<Style x:Key="DynamicOnDeviceLabelStyle" TargetType="Label" >
<Setter Property="FontSize" Value="{Binding LcModel.DynamicOnDeviceLabelFontSize}" />
</Style>
<Style TargetType="ContentPage" ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor" Value="{StaticResource MainColorGray}" />
</Style>
<Style TargetType="ContentView" ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor" Value="{StaticResource MainColorGray}" />
</Style>
<Style TargetType="Picker">
<Setter Property="TextColor" Value="Black"></Setter>
<Setter Property="TitleColor" Value="#7e8185"></Setter>
</Style>
<Style TargetType="SearchBar">
<Setter Property="TextColor" Value="Black"></Setter>
<Setter Property="BackgroundColor" Value="DarkGray"></Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
I'm trying to create a Style To apply the FontSize Property to Labels controles inside the application. However, i want the value of FontSize within the Style be determined deppending on the applicatrion execution environment. (If Tablet, i want a size, if cellphone i want another) To do this, i create the Model and ViewModel classes for the App class as follows.
Class: AppModel.cs
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace AppMsMovil.Models {
public class AppModel : INotifyPropertyChanged {
private double LcDblDynamicOnDeviceLabelFontSize;
public double DynamicOnDeviceLabelFontSize {
get => LcDblDynamicOnDeviceLabelFontSize;
set {
if (LcDblDynamicOnDeviceLabelFontSize != value) {
LcDblDynamicOnDeviceLabelFontSize = value;
OnPropertyChanged();
}
}
}
/// Para actualizar los controles enlazados
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Class: AppViewModel.cs
using AppMsMovil.Models;
using Xamarin.Forms;
namespace AppMsMovil.ViewModels {
public class AppViewModel {
public AppModel LcModel { get; set; }
public AppViewModel() {
LcModel = new AppModel();
SbSetDynamicOnDeviceProperties();
}
private void SbSetDynamicOnDeviceProperties() {
string StrOnDeviceLabelFontSize = Device.Idiom == TargetIdiom.Phone ? "Small" : Device.Idiom == TargetIdiom.Tablet ? "Medium" : "Medium";
LcModel.DynamicOnDeviceLabelFontSize = (double)new FontSizeConverter().ConvertFromInvariantString(StrOnDeviceLabelFontSize);
}
}
}
Finally, on the App class, i set the BindingContext with a ViewModel object.
Class: App.xaml.cs
using Xamarin.Forms;
using AppMsMovil.ViewModels;
namespace AppMsMovil {
public partial class App : Application {
public bool IsLoggedIn {
get {
return Current.Properties.ContainsKey("IsLoggedIn") && (bool)Current.Properties["IsLoggedIn"];
}
}
public App() {
InitializeComponent();
BindingContext = new AppViewModel();
MainPage = new AppShell();
}
protected override void OnStart() {
}
protected override void OnSleep() {
Current.Properties.Remove("IsLoggedIn");
}
protected override void OnResume() {
}
}
}
if i run the application, i can see that the Model and ViewModel class are created correctly, but, at i cannot see that the Get method of the DynamicOnDeviceLabelFontSize property on the AppModel.cs class is executed. so i think that the Setter's Value on my Style is not being assigned with that value.
(I confirm this because on the XAML file where im using the Style, is not taking the correct value)
NOTE: If i set a static value on Setter's Value of the Style, i can see that the Label control takes the correct value, so, this is not a Style problem, but it seems that the Setter's Value is not taking the value from Binding.
Question: Is it possible ti assign a value on a SetterĀ“s Value of the Style in Application.Resources using a Binding? or i'm wrong with this??
Any support will be welcome.
Regards!
UPDATE:
Solved using ideas from comments... this is the final solution:
<Style x:Key="DynamicOnDeviceLabelStyle" TargetType="Label" >
<Setter Property="FontSize" Value="{OnIdiom Phone=Small, Tablet=Medium}" />
</Style>
Thanks a lot!
Finally back at home, I want to show you some cool trick you can do with OnIdiom
1st: Using OnIdiom in XAML. You can use OnIdiom on any property of a Element in a view stack. This is useful to be able to manage different values depending on a device.
{OnIdiom Phone=Value, Tablet=Value}
2nd: There is also OnPlatform this enables you to do different things with different platforms.
{OnPlatform Android=Value, iOS=Value}
Further on you can combine these 2 to mix them together and this is how it looks combined
{OnIdiom Phone={OnPlatform Android=Value, iOS=Value}, Tablet={OnPlatform Android=Value, iOS=Value}}
You can go even a step further with styles and implement something along the line of this. You'll be able to determine if device is General Size or Small Size.
Inside App.xaml make sure to add x:Name="dictionary to your main Application.Resources otherwise you wont be able to load the custom dictionaries in the code behind.
<Application.Resources>
<ResourceDictionary x:Name="dictionary"> <----- IMPORTANT
</ResourceDictionary>
</Application.Resources>
Inside App.xaml.cs add this to the class. You want to determine what the screen size is, so we set couple of const of sizes. Create a method IsASmallDevice that will return true if device is small otherwise false. We then want to load the styles with LoadStyles method by using DeviceInfo class and checking which platform we're working on to load correct styles. Once we have things understood we want to merge our custom ResourceDictionary with our AppResource dictionary by doing MergedDictionaries.Add(our instance of ResourceDictionary).
public partial class App : Application
{
const int smallWightResolution = 768;
const int smallHeightResolution = 1280;
public App()
{
InitializeComponent();
LoadStyles();
MainPage = new AppShell();
}
void LoadStyles()
{
var isSmall = IsASmallDevice();
if (DeviceInfo.Platform == DevicePlatform.Android)
{
if (isSmall)
dictionary.MergedDictionaries.Add(AndroidSmallDeviceStyles.SharedInstance);
else
dictionary.MergedDictionaries.Add(AndroidDeviceStyles.SharedInstance);
}else if (DeviceInfo.Platform == DevicePlatform.iOS)
{
if (isSmall)
dictionary.MergedDictionaries.Add(iOSSmallDeviceStyles.SharedInstance);
else
dictionary.MergedDictionaries.Add(iOSDeviceStyles.SharedInstance);
}
}
public static bool IsASmallDevice()
{
var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
var width = mainDisplayInfo.Width;
var height = mainDisplayInfo.Height;
return (width <= smallWightResolution && height <= smallHeightResolution);
}
}
Next you want to create Content Page and change it up like this. Make the Content Page into a ResourceDictionary allowing you to do the same as the App ResourceDictionary but seperated.
<?xml version="1.0" encoding="UTF-8"?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Class.Styles.AndroidDeviceStyles">
</ResourceDictionary>
Inside that Content Page.xaml.cs add this to enable it as ResourceDictionry and have a static property to make a new instance of that class allowing you to call it in the App depending on the device size that was loaded.
public partial class AndroidDeviceStyles : ResourceDictionary
{
public static AndroidDeviceStyles SharedInstance { get; } = new AndroidDeviceStyles();
public AndroidDeviceStyles()
{
InitializeComponent();
}
}
Inside that new ResourceDictionary this is how you want to set new styles.
<?xml version="1.0" encoding="UTF-8"?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Class.Styles.AndroidDeviceStyles">
<Style x:Key="Public Key To Access Through Static Resource"
TargetType="Your Targer Type e.g Grid">
<Setter Property="WidthRequest"
Value="100" />
<Setter Property="HeightRequest"
Value="100" />
<Setter Property="BackgroundColor"
Value="Red" />
</Style>
</ResourceDictionary>
This is how I usually do mine, one for each platform. I've found that it is almost impossible to get it right with a single style between each platform so yes I know it might be a lot of work to begin with but once it is done you'll be very happy with yourself having this kid of separation and control over each style in your application.
If you got any more questions about this please let me know in the comments I will be more than happy to show you more and explain things I might of forgot to mention in this answer.
Finally found a solution...
The model and viewmodel classes are not necessary, i only need to change this line.
Solved using ideas from comments... this is the final solution:
<Style x:Key="DynamicOnDeviceLabelStyle" TargetType="Label" >
<Setter Property="FontSize" Value="{OnIdiom Phone=Small, Tablet=Medium}" />
</Style>
Thanks a lot!
I am making a custom control based on a button, and I want to bind the width of the button to a property of the class. I have looked at this, this, and this, but they either aren't what I'm looking for, or don't work.
Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControl">
<Style TargetType="{x:Type local:MyCustomControl}" BasedOn = "{StaticResource {x:Type Button}}">
<Setter Property = "Background" Value = "LightSalmon" />
<Setter Property = "Foreground" Value = "Blue"/>
<Setter Property = "Height" Value = "50"/>
<Setter Property = "Width" Value = "{Binding MyCustomControl.TextBinding}"/>
<Setter Property = "VerticalAlignment" Value = "Top"/>
<Setter Property = "Margin" Value="10"/>
</Style>
</ResourceDictionary>
MyCustomControl.cs
namespace CustomControl
{
public class MyCustomControl : Button
{
double m_textBinding = 50;
public double TextBinding
{
get { return m_textBinding; }
set { m_textBinding = value; }
}
static MyCustomControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl),
new FrameworkPropertyMetadata(typeof(MyCustomControl)));
}
}
}
If need be, I can just use the "setter" function, and specify manually, "Width = value;", but I would prefer to use a binding. Currently the "{Binding MyCustomControl.TextBinding}" isn't working.
This should work:
<Setter Property="Width"
Value="{Binding TextBinding, RelativeSource={RelativeSource Self}}"/>
[My main idea of this is to set visible/hidden for a usercontrol. I used WPF with Mvvmcross.]
I have a user control call SpinningWheelUserControl. I want to visible/hide it with the datatrigger. Below is my xaml code in App.xaml
In App.xaml I have added the namespace of the usercontrol as below.
xmlns:local="clr-namespace:UserControl"
The following is a style setting for my usercontrol.
<Style x:Key="SpinningWheel" TargetType="{x:Type local:SpinningWheelUserControl}" >
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="true">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding IsVisible}" Value="false">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
There is a class for SpinningWheel
public class SpinningWheelViewModel
: MvxNotifyPropertyChanged
{
public bool IsVisible { get; set; }
}
In a constructor of parent class, i use like this code
SpinningWheel = new SpinningWheelViewModel();
SpinningWheel.IsVisible = false;
The usercontrol is hidden for a first running. But when I change the IsVisble to true, it has no change.
SpinningWheel.IsVisible = true
You need to set Visibility instead of IsVisible like this:
SpinningWheel.Visibility = Visibility.Visible;
Oh now i see, you are setting your custom IsVisibility instead of UIElement property.
Issue with your code is you haven't raised PropertyChanged to let UI know that some property change in underlying source object.
private bool isVisible;
public bool IsVisible
{
get { return isVisible;}
set
{
if(isVisible != value)
{
isVisible = value;
RaisePropertyChanged("IsVisible");
}
}
}
Assuming you have implemented INotifyPropertyChanged on your class.
This n+1 video called N=34 : a data-bound busy dialog shows exactly how to do what you are trying to do.
I need to create a custom property meaning rather using
<Style x:Key="ABC" TargetType="Rectangle">
<Setter Property="Fill" Value="Red"/>
</Style>
I like to have something like Rectangle and assign it an ID so later when it is dropped on Canvas I can retrieve its ID.
<Style x:Key="ABC" TargetType="Rectangle">
<Setter Property="Fill" Value="Red"/>
**<Setter Property="ID" Value="1234567890-ABC"/>**
</Style>
How can I define that custom property?
Regards,
Amit
Define a custom attached property in a separate class:
public class Prop : DependencyObject
{
public static readonly DependencyProperty IDProperty =
DependencyProperty.RegisterAttached("ID", typeof(string), typeof(Prop), new PropertyMetadata(null));
public static void SetID(UIElement element, string value)
{
element.SetValue(IDProperty, value);
}
public static string GetID(UIElement element)
{
return (string)element.GetValue(IDProperty);
}
}
Then you can use this:
<Setter Property="local:Prop.ID" Value="1234567890-ABC"/>
local must be defined in the root element of your XAML appromimately like this:
xmlns:local="clr-namespace:AttPropTest"
where AttPropTest is the namespace of the assembly.
In code, you can determine the ID with Prop.GetID(myRect).
I've created a WPF UserControl which contains a Button and a ComboBox. I'd like to change the style of both, depending on the position of the mouse, so the UIElement with the mouse over is coloured Black and the other is coloured Red. If neither are styled then the default styling will apply.
Don't worry, this nightmarish colour scheme is just to illustrate the concept!
Thanks in advance for your help.
XAML
<UserControl x:Class="WpfUserControlSample.ToolbarButtonCombo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfUserControlSample"
x:Name="Control"
mc:Ignorable="d"
d:DesignHeight="30">
<UserControl.Resources>
<Style TargetType="{x:Type local:ToolbarButtonCombo}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsButtonMouseOver}" Value="True">
<Setter Property="ButtonStyle" Value="Black"/>
<Setter Property="ComboStyle" Value="Red"/>
</DataTrigger>
<!--
<DataTrigger Binding="{Binding IsComboMouseOver}" Value="True">
<Setter Property="ButtonStyle" Value="Red"/>
<Setter Property="ComboStyle" Value="Black"/>
</DataTrigger>
-->
</Style.Triggers>
</Style>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Height="30">
<Button Name="btn" Background="{Binding ButtonStyle,ElementName=Control,Mode=OneWay}">
Test
</Button>
<ComboBox Name="cmb" Background="{Binding ComboStyle,ElementName=Control,Mode=OneWay}"></ComboBox>
</StackPanel>
</UserControl>
Codebehind:
namespace WpfUserControlSample
{
public partial class ToolbarButtonCombo : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public ToolbarButtonCombo()
{
InitializeComponent();
btn.MouseEnter += new MouseEventHandler(btn_MouseChanged);
btn.MouseLeave += new MouseEventHandler(btn_MouseChanged);
}
void btn_MouseChanged(object sender, MouseEventArgs e)
{
OnPropertyChanged("IsButtonMouseOver");
}
public bool IsButtonMouseOver
{
get { return btn.IsMouseOver; }
}
public static readonly DependencyProperty IsButtonMouseOverProperty =
DependencyProperty.Register("IsButtonMouseOver", typeof(string), typeof(ToolbarButtonCombo), new PropertyMetadata("false"));
public string ButtonStyle { get; set; }
public static readonly DependencyProperty ButtonStyleProperty =
DependencyProperty.Register("ButtonStyle", typeof(string), typeof(ToolbarButtonCombo));
public string ComboStyle { get; set; }
public static readonly DependencyProperty ComboStyleProperty =
DependencyProperty.Register("ComboStyle", typeof(string), typeof(ToolbarButtonCombo));
}
}
There are a two problems.
First your DataTrigger bindings do not look correct. They are looking for the IsButtonMouseOver on the DataContext, not the associated control. You'd need to use:
<DataTrigger Binding="{Binding IsButtonMouseOver, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="ButtonStyle" Value="Black"/>
<Setter Property="ComboStyle" Value="Red"/>
</DataTrigger>
Or:
<Trigger Property="IsButtonMouseOver" Value="True">
<Setter Property="ButtonStyle" Value="Black"/>
<Setter Property="ComboStyle" Value="Red"/>
</Trigger>
The other is your IsButtonMouseOver is not implemented correctly. You should do something like:
public static readonly DependencyProperty IsButtonMouseOverProperty = DependencyProperty.Register("IsButtonMouseOver",
typeof(bool), typeof(ToolbarButtonCombo), new PropertyMetadata(false));
public bool IsButtonMouseOver
{
get { return (bool)this.GetValue(IsButtonMouseOverProperty); }
set { this.SetValue(IsButtonMouseOverProperty, value); }
}
void btn_MouseChanged(object sender, MouseEventArgs e)
{
this.IsButtonMouseOver = this.btn.IsMouseOver;
}
Or even more correctly, make the IsButtonMouseOver a read-only dependency property like so:
private static readonly DependencyPropertyKey IsButtonMouseOverPropertyKey = DependencyProperty.RegisterReadOnly("IsButtonMouseOver",
typeof(bool), typeof(ToolbarButtonCombo), new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty IsButtonMouseOverProperty = ToolbarButtonCombo.IsButtonMouseOverPropertyKey.DependencyProperty;
public bool IsButtonMouseOver {
get { return (bool)this.GetValue(IsButtonMouseOverProperty); }
private set { this.SetValue(IsButtonMouseOverPropertyKey, value); }
}
Your other properties (ButtonStyle and ComboStyle) would need to be properly implemented also, and their get/set methods are not backed by the dependency property.