Use Binding Context on Application Resources - c#

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!

Related

Binding foreground color of control to mouse hover

I have a user control for which I have to change color, based on mouse hover, click or none. Following MVVM. This is the code I have:
User control in XAML
<userControls:NC DataContext="{Binding NCVM}" >
</userControls:NC>
User Control View Model
public class NCVM : ObservableObject
{
public NCVM()
{
}
private NCState _currentState = NCState.InActive;
public NCState CurrentState
{
get => _currentState;
set
{
_currentState = value;
switch (_currentState)
{
case NCState.InActive:
ForegroundColor = System.Windows.Media.Brushes.LightGray;
IsActive = false;
break;
case NCState.Active:
ForegroundColor = System.Windows.Media.Brushes.White;
IsActive = true;
break;
case NCState.Hovered:
ForegroundColor = System.Windows.Media.Brushes.White;
IsActive = false;
break;
default:
ForegroundColor = System.Windows.Media.Brushes.LightGray;
IsActive = false;
break;
}
}
}
public bool _isActive;
public bool IsActive
{
get => _isActive;
set => SetProperty(ref _isActive, value);
}
private System.Windows.Media.Brush _foregroundColor = System.Windows.Media.Brushes.LightGray;
public System.Windows.Media.Brush ForegroundColor
{
get => _foregroundColor;
set => SetProperty(ref _foregroundColor, value);
}
}
Main Window View Model
public class MWVM : BVM
{
#region Private Variables
private NCVM _NCVM = new();
#endregion
public MWVM()
{
NCVM.CurrentState = NCState.Active;
}
#region Public Properties
public NCVM NCVM
{
get => _NCVM;
set => SetProperty(ref _NCVM, value);
}
#endregion
}
Right now, it's getting preset as active for checking. Now, I have to make it manual so it changes on hover, but not getting how to do with binding.
The MVVM pattern is about separating the user interface (view) from the data and application logic itself. Your example violates MVVM in that it stores the brushes and the visual states in a view model. The view model should only expose data and commands to be bound, but not user interface elements and it must not contain logic to that relates to the user interface just like managing visual states or appearance. It is too often misunderstood as creating a view model and just putting everything there.
In your case, I think that you can solve your issue by moving everything into a style. The following XAML should show your userControls:NC. There are triggers for different states like Disabled, Hover / Mouse Over. Please note that you need to set a Background, otherwise the control does not participate in hit testing and e.g. the IsMouseOver property will not be True even if you hover over it. For no background use Transparent (which is not equal to not setting a value).
<UserControl ...>
<UserControl.Style>
<Style TargetType="{x:Type userControls:NC}">
<!-- Background must be set at least to "Transparent" -->
<Setter Property="Background" Value="Black"/>
<!-- Default -->
<Setter Property="Foreground" Value="LightGray"/>
<Style.Triggers>
<!-- Hovered -->
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="White"/>
</Trigger>
<!-- Disabled -->
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="LightGray"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Style>
<!-- Dummy element for demonstration purposes of foreground -->
<TextBlock Text="This text shows the foreground"/>
</UserControl>
You may take a look at EventTrigger, or Triggers in general to style your control.
*Edit:
A little example, MVVM not considered, just for you to get a glimpse at triggers.
UserControl:
<UserControl x:Class="WpfApp1.UserControl1"
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:WpfApp1"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type={x:Type local:UserControl1}}"
Height="200" Width="400">
<UserControl.Style>
<Style TargetType="UserControl">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMyPropSet}" Value="True">
<Setter Property="Background" Value="Turquoise"/>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Style>
<GroupBox Header="I am your usercontrol">
<Button Width="100" Height="35" Content="Toggle Property" Click="Button_Click"/>
</GroupBox>
</UserControl>
and code-behind:
public partial class UserControl1 : UserControl, INotifyPropertyChanged
{
public UserControl1()
{
InitializeComponent();
DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
public bool IsMyPropSet { get; set; }
private void Button_Click(object sender, RoutedEventArgs e)
{
IsMyPropSet = !IsMyPropSet;
RaisePropertyChanged(nameof(IsMyPropSet));
}
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

WPF styling custom control

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"

Bind a property to another property of a custom control

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}}"/>

How to set Button.Command from a ResourceDictionary?

I'm trying to implement a hamburger button by myself in a Windows 10 app. I'm running into a little trouble with my ResourceDictionary when trying to set the Command property of a Button (via a style). Here is my code:
Hamburger.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Octopie.Styles.Hamburger"
xmlns:local="using:Octopie.Styles">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Square.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style x:Key="HamburgerStyle" TargetType="Button" BasedOn="{StaticResource SquareStyle}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Command" Value="{Binding OnClicked}"/> <!--This is the part that's having issues-->
<Setter Property="Content" Value=""/>
<Setter Property="FontFamily" Value="Segoe MDL2 Assets"/>
</Style>
</ResourceDictionary>
Hamburger.xaml.cs
namespace Octopie.Styles
{
public sealed partial class Hamburger : ResourceDictionary
{
public Hamburger()
{
this.InitializeComponent();
}
public ICommand OnClicked => new ClickedCommand();
private class ClickedCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter) =>
parameter is Button;
public void Execute(object parameter)
{
var button = (Button)parameter;
// Walk up the tree until we reach a SplitView
FrameworkElement parent = button;
do
parent = parent.Parent as FrameworkElement;
while (!(parent is SplitView));
var splitView = (SplitView)parent;
splitView.IsPaneOpen = !splitView.IsPaneOpen;
}
}
}
}
For some reason the binding for the Command property doesn't seem to be working; when I set a breakpoint inside the Execute method and click the button, the breakpoint is never hit. I tried adding a DataContext="{Binding RelativeSource={RelativeSource Self}}" to the top of the XAML file, but for some reason ResourceDictionary doesn't seem to support DataContext.
tl;dr: What can I do to make the Button.Command property bind correctly to OnClicked within the setter?
Like Mike said, usually we won't set Button.Command in ResourceDictionary. A hamburger button may not only be in SplitView but can be in another place and then you may need bind another command. So you can refer to Mike's suggestion.
But if you do want to set it in ResourceDictionary, you can try like following:
Firstly, in your case, your command is fixed, you can declare your ClickedCommand as a public class, then in the Style,set the Command like:
<Setter Property="Command">
<Setter.Value>
<local:ClickedCommand />
</Setter.Value>
</Setter>
After this, you can use your command, but this won't fix your problem as in ClickedCommand, you use parameter to retrieve the Button, but the parameter is not the "sender" of the Command, but the object passed with CommandParameter property. So we need set this in the Style.
However, Bindings in Style Setters are not supported in UWP Apps. See Remarks in Setter class:
The Windows Runtime doesn't support a Binding usage for Setter.Value (the Binding won't evaluate and the Setter has no effect, you won't get errors, but you won't get the desired result either).
A workaround for this is using attached property to set up the binding in code behind for you. For example:
public class BindingHelper
{
public static readonly DependencyProperty CommandParameterBindingProperty =
DependencyProperty.RegisterAttached(
"CommandParameterBinding", typeof(bool), typeof(BindingHelper),
new PropertyMetadata(null, CommandParameterBindingPropertyChanged));
public static bool GetCommandParameterBinding(DependencyObject obj)
{
return (bool)obj.GetValue(CommandParameterBindingProperty);
}
public static void SetCommandParameterBinding(DependencyObject obj, bool value)
{
obj.SetValue(CommandParameterBindingProperty, value);
}
private static void CommandParameterBindingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
BindingOperations.SetBinding(d, Button.CommandParameterProperty, new Binding { RelativeSource = new RelativeSource() { Mode = RelativeSourceMode.Self } });
}
}
}
Then in Style, using
<Setter Property="local:BindingHelper.CommandParameterBinding" Value="True" />
will set the Button as CommandParameter. Your Hamburger.xaml may like:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Octopie.Styles">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Square.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="HamburgerStyle" TargetType="Button" BasedOn="{StaticResource SquareStyle}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Command">
<Setter.Value>
<local:ClickedCommand />
</Setter.Value>
</Setter>
<Setter Property="local:BindingHelper.CommandParameterBinding" Value="True" />
<Setter Property="Content" Value="" />
<Setter Property="FontFamily" Value="Segoe MDL2 Assets" />
</Style>
</ResourceDictionary>
I delete x:Class="Octopie.Styles.Hamburger" and Hamburger.xaml.cs as there is no need to use code-behind for your ResourceDictionary.
Now we can use this ResourceDictionary in our page like:
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Hamburger.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<SplitView DisplayMode="CompactOverlay" IsPaneOpen="True">
<SplitView.Pane>
<StackPanel>
<Button Style="{StaticResource HamburgerStyle}" />
</StackPanel>
</SplitView.Pane>
</SplitView>
</Grid>
But there is another problem in Execute method of ClickedCommand. In this method, you've used FrameworkElement.Parent to retrieve the SplitView. But
Parent can be null if an object was instantiated, but is not
attached to an object that eventually connects to a page object root.
Most of the time, Parent is the same value as returned by
VisualTreeHelper APIs. However, there may be cases where Parent
reports a different parent than VisualTreeHelper does.
And in your case, you need use VisualTreeHelper.GetParent to get the SplitView. We can use a helper method to do this:
public static T FindParent<T>(DependencyObject child) where T : DependencyObject
{
//get parent item
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
return parent;
else
return FindParent<T>(parentObject);
}
Then in Execute method using:
public void Execute(object parameter)
{
var button = (Button)parameter;
var splitView = FindParent<SplitView>(button);
splitView.IsPaneOpen = !splitView.IsPaneOpen;
}
Now the HamburgerStyle will work as you want.
What the hell?
You're going about this all wrong. You don't need to declare a new ICommand in a ResourceDictionary, it simply doesn't belong there. It belongs in your View Model, or whatever the Button.DataContext is set to.
The purpose of a Style is to control the look and feel of your controls, they should not explicitly set their own behaviours (commands).
Let me show you an example. You should declare your button like this:
<Button Style="{StaticResource HamburgerStyle}" Command="{Binding ClickedCommand}"/>
Where ClickedCommand is an object in your View Model.
Your HamburgerStyle should not set it's own Command property, otherwise you are limiting your Button to one single implementation of ICommand, this is unwise.

Setting User Preferences for font family to a wpf mvvm application

How to set User Preferences for font family to a wpf mvvm application in c#?
you can create a global Style for TargetType Window
and there set the Preference .
the resource :
<Application.Resources>
<Style TargetType="Window" x:Key="WindowStyle">
<Setter Property="FontFamily" Value="{Binding FontFamilyPrefernce}" />
</Style>
</Application.Resources>
the View :
<Window Style="{StaticResource WindowStyle}">
<Grid>
<TextBox />
</Grid>
</Window>
the ViewModel :
public SomeViewModel()
{
FontFamilyPrefernce = new FontFamily("Algerian");
}
private FontFamily fontFamilyPrefernce;
public FontFamily FontFamilyPrefernce
{
get {return fontFamilyPrefernce ;}
set
{
fontFamilyPrefernce = value;
OnPropertyChanged("FontFamilyPrefernce");
}
}
hope this helps ..

Categories

Resources