Change colour of Switch and Picker from ViewModel - c#

I have implemented MVVM pattern with property for colour SColor. This property is attached to Picker.
<Switch IsToggled="{Binding IsCounted}" OnColor="{Binding SColor}"></Switch>
<Entry Text="{Binding TimeS}" BackgroundColor="{Binding SColor}"></Entry>
<Picker ItemsSource="{Binding PColors}" SelectedItem="{Binding SelectedColor}"
ItemDisplayBinding="{Binding ColorName}" BackgroundColor="{Binding SColor}"
Background="{Binding SColor}"></Picker>
In ViewModel:
private Color sColor;
public Color SColor
{
get => this.sColor;
set
{
this.sColor = value;
this.OnPropertyChanged();
}
}
private ColorModel selectedColor;
public ColorModel SelectedColor
{
get => this.selectedColor;
set
{
this.selectedColor = value;
this.OnPropertyChanged();
}
}
and ColorModel.cs
public class ColorModel
{
public string ColorName { get; set; }
public string ColorHex { get; set; }
}
For some reason Colour of Switch and Picker are not changing from ViewModel where Entry background colour does. See screenshot below. I have selected Red colour and Entry backgound clour has been updated, but Switch and Picker are not. For Switch I have noticed, that after hovering mouse on, colour does change and for Picker itself switching between pages updates selected colour. Is it MAUI bug or feature or I am doing something wrong?

For some reason Colour of Switch and Picker are not changing from
ViewModel where Entry background color does.
I did a test on my side,the OnColor of Switch will update automatically.
And the BackgroundColor of both Entry and Picker will not update automatically.
From the source code of Switch in maui,we could find that:
public static readonly BindableProperty OnColorProperty = BindableProperty.Create(nameof(OnColor), typeof(Color), typeof(Switch), null,
propertyChanged: (bindable, oldValue, newValue) =>
{
((IView)bindable)?.Handler?.UpdateValue(nameof(ISwitch.TrackColor));
});
public Color OnColor
{
get { return (Color)GetValue(OnColorProperty); }
set { SetValue(OnColorProperty, value); }
}
it means that property OnColor is a BindableProperty,so if we change the value of the binded property OnColor, the UI will update automatically.
<Switch IsToggled="{Binding IsCounted}" OnColor="{Binding SColor}"></Switch>
And if we review the source code of Picker and Entry, we will find that there is no BindableProperty called BackgroundColor in both views.
So, if we use binding method to update BackgroundColor, the UI will not refresh automatically.
You can create new features about this here.
Of course,if you want to change the background color, you can try to use Triggers.
Thanks for your support and feedback.

Related

UWP: How to programmatically set value of bound struct property without loosing binding?

I have a ContentDialog with a few controls, one of them a color picker, where the user can pick a color.
When the dialog loads I want to initialize the color picker with a given color (from a previous selection), there is also a rectangle control which shows the selected color.
The color picker is bound to a property in the view model (TwoWay) and the rectangle background color is also bound (OneWay) to the same property.
<Viewbox Margin="5" MaxWidth="100" Stretch="Fill">
<ColorPicker x:Name="fontColorPicker"
ColorSpectrumShape="Ring"
IsColorPreviewVisible="False"
IsColorChannelTextInputVisible="False"
IsHexInputVisible="False" Color="{x:Bind ViewModel.SelectedColor, Mode=TwoWay}" ColorChanged="fontColorPicker_ColorChanged" />
</Viewbox>
<Rectangle Height="50" Width="50" Margin="10,0,0,0" StrokeThickness="1" Stroke="DarkGray">
<Rectangle.Fill>
<SolidColorBrush Color="{x:Bind ViewModel.SelectedColor, Mode=OneWay}"/>
</Rectangle.Fill>
</Rectangle>
All is fine until I want to set the initial color for the color picker. As Color is a struct, I cannot change the A, R, G, B properties, I have to instanciate a new struct and assign it to the property. But with this assignment the binding will get removed.
This is how I currently change the value in the view model, to initialize the value (settings.Color is not a Windows.UI.Color, but a class from another imaging library, so I have to convert the values):
// Font color
if (settings.Color != null)
{
var pickerColor = new Windows.UI.Color
{
A = settings.Color.A,
R = settings.Color.R,
G = settings.Color.G,
B = settings.Color.B
};
ViewModel.SelectedColor = pickerColor;
}
I know, I could re-create the binding after this so make it work again, but I am sure there must be a more clean approach without the need for this to happen.
You can make the ViewModel class implement the INotifyPropertyChanged interface:
public class ViewModel : INotifyPropertyChanged
{
private Color _selectedColor;
public Color SelectedColor
{
get => _selectedColor;
set
{
_selectedColor = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
In this way, when you bind SelectedColor through OneWay, changes to SelectedColor will notify the UI to also change.

Custom control does not update background color Xamarin Forms

I have created a custom control that i want to change color after a click. I can successfully load it, but once I run my function and want to change the color, nothing happens. When i try to do it with a regular element (button, label) it works.
Custom control (that is a Grid with a simple label inside):
public partial class CustomGrid : Grid
{
public static readonly BindableProperty ItemProperty = BindableProperty.Create(nameof(Item), typeof(Item), typeof(CustomGrid), propertyChanged: ItemChanged);
public static readonly BindableProperty CustomColorProperty = BindableProperty.Create(nameof(IsAnonymousSubColor), typeof(Color), typeof(CustomGrid), propertyChanged: CustomColorChanged);
public Color CustomColor
{
get { return (Color)GetValue(CustomColorProperty); }
set { SetValue(CustomColorProperty, value); }
}
static void CustomColorChanged (object bindable, object oldValue, object newValue)
{
var x = bindable as CustomGrid;
if (x.Item != null)
{
x.myLabelInMyXaml.BackgroundColor = x.CustomColor;
}
}
static void ItemChanged (object bindable, object oldValue, object newValue)
{
var x = bindable as CustomGrid;
}
public Item Item
{
get { return (Item) GetValue(ItemProperty); }
set { SetValue(ItemProperty, value); }
}
public CustomGrid()
{
InitializeComponent();
}
}
Here is my xaml, here i bind it to the viewmodel color code (binding works well on other elements, even if i try it inside the same stacklayout).
<StackLayout BackgroundColor="Transparent"
Padding="0,10,0,0"
VerticalOptions = "StartAndExpand"
BindableLayout.ItemsSource="{Binding newsService.FeedList}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout>
<controls:CustomGrid Item ="{Binding .}"
CustomColor = "{Binding BindingContext.CustomColorViewModel, Source={x:Reference ParentView}}" />
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
ViewModel:
private Color _CustomColorViewModel;
public Color CustomColorViewModel
{
get { return _CustomColorViewModel; }
set
{
_CustomColorViewModel = value;
RaisePropertyChanged("CustomColorViewModel");
}
}
And i change it after loading it:
public void ChangeColor ()
{
CustomColorViewModel = Color.Red;
}
XAML of custom control:
<?xml version="1.0" encoding="UTF-8"?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:Neutral.Controls"
xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
xmlns:fftransformations="clr-namespace:FFImageLoading.Transformations;assembly=FFImageLoading.Transformations"
xmlns:yummy="clr-namespace:Xamarin.Forms.PancakeView;assembly=Xamarin.Forms.PancakeView"
x:Name="ParentView"
x:Class="Project.Controls.CustomGrid">
<Label x:Name = "myLabelInMyXaml" BackgroundColor = "{Binding CustomColorViewModel}"/>
</Grid>
But the custom control background color does not change. It works when i initially load, but not when i try to update it. Note that i have no issue with other elements, only this custom control.
Not sure why it does not update the color.
I notice you used CustomColor property in stacklayout, but you add the IsAnonymousSubColor property in your CustomColor background code.
I change your CustomColor background code like following format(Just test function to change the color).
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CustomGrid : Grid
{
public static readonly BindableProperty CustomColorProperty = BindableProperty.Create(nameof(CustomColor), typeof(Color), typeof(CustomGrid), propertyChanged: CustomColorChanged);
public Color CustomColor
{
get { return (Color)GetValue(CustomColorProperty); }
set { SetValue(CustomColorProperty, value); }
}
static void CustomColorChanged(object bindable, object oldValue, object newValue)
{
var x = bindable as CustomGrid;
x.myLabelInMyXaml.BackgroundColor = x.CustomColor;
}
public CustomGrid()
{
InitializeComponent();
}
}
Here is running GIF.
This is where the issue is:
x.myLabelInMyXaml.BackgroundColor = x.CustomColor;
Change it to:
x.myLabelInMyXaml.BackgroundColor = (Color) newValue;
I think you may have an issue with the binding context.
Hard to say without seeing all of the code in context.
First of all, why are you calling a property a view model? The name doesn't really matter, but it is confusing as a property is not a view model, and without seeing the class that that property is in, it is hard to say what is going on here.
My suspicion is that the issue is here:
<controls:CustomGrid Item ="{Binding .}"
CustomColor = "{Binding BindingContext.CustomColorViewModel, Source={x:Reference ParentView}}" />
I think your binding code for the CustomColor should instead be (assuming your parent view is really named ParentView):
CustomColor = "{Binding Source={x:Reference ParentView}, Path=BindingContext.CustomColorViewModel}"
But again that is based on missing some vital code/information, but hopefully will at least move you in the right direction, if not be the solution.

How to set the FontStyle of a TextBlock via Binding (MVVM)

My snipped code of the XAML:
<TextBlock Text="{Binding Name}" Foreground="{Binding FontColor}" FontStyle="{Binding FontStyleTreeItem}"/>
Snipped code Class TreeItem:
public System.Windows.FontStyles FontStyleTreeItem {get;set}
I want to assign the property "FontStyleTreeItem" something like:
treeItem.FontStyleTreeItem = System.Windows.FontStyles.Italic;
But this doesn't work because "System.Windows.FontStyles" is static. But I can't figure out how to give a good solution to set the above property.
I also tried to set the property as a FontStyle, so without the s at the end (FontStyles), but then the fontstyle of the textblock doesn't change.
public FontStyle FontStyleTreeItem { get { return FontStyle.Italic; } }
Can somebody see what I'm missing?
Already thanks.
The type of the property should be System.Windows.FontStyle. It may still return a static value such as FontStyles.Italic:
public System.Windows.FontStyle FontStyleTreeItem { get { return System.Windows.FontStyles.Italic; } }
If you define the property like this:
public System.Windows.FontStyle FontStyleTreeItem { get; set; }
...you can set it to any FontStyle value, e.g.:
FontStyleTreeItem = FontStyles.Italic;
If you set it dynamically at runtime, you need to implement the INotifyPropertyChanged interface for the font style to change.

Entity framework enum - binding to WPF - show selected item

I would like to ask for help with this task:
I have a Model Class with enum.
public enum ColorEnum { not set, black, white, red}
public ColorEnum Color {get; set }
Now I am creating WPF window - easy form for edit a car and I would like to bind the enum items to a comboBox. I am using a MVVM architecture. I am not sure, what to put into EditCarViewModel - I don't know how to reference the enum from the Entity Framework.
protected string color;
public string Color
{
get
{
return color;
}
set
{
color = value;
NotifyPropertyChanged();
}
}
Into the EditCarWindow.xaml.cs I added this code and in the ComboBox I can choose the options (colors) from the enum:
public EditCarUserControl(int idCar=0)
{
InitializeComponent();
this.DataContext = new EditCarViewModel(idCar);
ComboBoxColor.ItemsSource = Enum.GetValues(typeof(Car.ColorEnum));
}
But the problem is - I don't know how to let the color which is set in DB to be selected in the ComboBox. This does not work.
<ComboBox x:Name="ComboBoxColor" Grid.Column="1" Grid.Row="4" Margin="3" SelectedItem="{Binding Color, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
I guess the problem is in the ViewModel - Of course I can't have the fuel as a string - but what should I do?
Any help would be appreciated.

Silverlight: binding on complex property

First of all i will try to explain what i am doing. I am trying to draw a chess board. I have a user controll for cell
<Grid x:Name="LayoutRoot">
<Border BorderThickness="0" Margin="0" Background="{Binding CellColor, ElementName=userControl, Mode=TwoWay}"/>
<Border x:Name="ValidMoveMarker" BorderThickness="0" Margin="0" Background="#FFC1CAB4" Opacity="0"/>
<Image x:Name="img" Source="{Binding source, ElementName=userControl, Mode=TwoWay}" Cursor="Hand"/>
In code behind of this CellControl i have 2 dpProperties
public eColor? PieceColor
{
get { return (eColor?)GetValue(PieceColorProperty); }
set { SetValue(PieceColorProperty, value);}
}
public static readonly DependencyProperty PieceColorProperty = DependencyProperty.Register("PieceColor", typeof(eColor?), typeof(CellControl), null);
public eType? PieceType
{
get { return (eType?)GetValue(PieceTypeProperty); }
set { SetValue(PieceTypeProperty, value);}
}
public static readonly DependencyProperty PieceTypeProperty = DependencyProperty.Register("PieceType", typeof(eType?), typeof(CellControl), null);
where eColor and eType are enumerators. Here I also have one property
public ImageSource source
{
get
{
if (PieceColor == eColor.White)
{
switch (PieceType)
{
case eType.Pawn:
return new BitmapImage(new Uri("/PO.PC;component/Images/chess_piece_white_pawn_T.png", UriKind.Relative));
case eType.Knight:
return new BitmapImage(new Uri("/PO.PC;component/Images/chess_piece_white_knight_T.png", UriKind.Relative));
...
default:
return null;
}
}
else
{
switch (PieceType)
{
case eType.Pawn:
}
}
}
Now problem is when i try to use the control like this
<PP_Controls:CellControl PieceType="{Binding type, Mode=TwoWay}" PieceColor="{Binding color, Mode=TwoWay}"
where
private eColor? _color;
public eColor? color
{
get { return _color; }
set
{
_color = value;
OnPropertyChanged("color");
}
}
private eType? _type;
public eType? type
{
get { return _type; }
set
{
_type = value;
OnPropertyChanged("type");
}
}
nothings happens. But if i use control like this
<PP_Controls:CellControl PieceType="Bishop" PieceColor="Black"
it is working perfectly. Am I missing something in my bindings? Is this because "source" property is not dependency property itself? How can I workaround my problem?
Your target properties are dependency properties, and the source properties are CLR properties implementing INotifyPropertyChanged, so your binding {Binding type} etc should work - assuming that the DataContext to your "use with binding" is the type with the color/type properties. You should be able to tell if these bindings are failing by looking at the Output window when you run your application under the debugger (in Silverlight 5 you could also use a binding breakpoint, or otherwise you can apply a trivial ValueConverter to the binding to set a breakpoint for debugging).
However your control's source property depends on two other properties in a 'lazy' fashion. You are binding to the source property, but nothing will cause this binding to update when the property's computed value changes. You should add a dependency property changed handler to PieceColor and PieceType which calls OnPropertyChanged("source") (or equivalently convert it to a DP or notifying property, and explicitly recompute the value).

Categories