How to style a button based on a property of the window - wpf

I have a simple WPF application with a Window. This window has a dependency property.
public static readonly DependencyProperty ShiftProperty;
static VirtualKeyboard()
{
ShiftProperty = DependencyProperty.Register("Shift", typeof(bool), typeof(VirtualKeyboard));
}
public bool Shift
{
get { return (bool)GetValue(ShiftProperty); }
set { SetValue(ShiftProperty, value); }
}
Now, on this window I have a button that I wish to visually display if Shift is True or not, by applying a style.
I admit to not being very experienced in WPF, but I believe this can be solved using Data triggers. My problem is hooking it up.
Here is the xaml for the button.
<Button Grid.Row="4" Grid.ColumnSpan="2" Grid.Column="0" Command="local:VirtualKeyboard.ShiftButtonPressedCommand" Content="Shift" Name="ShiftButton">
<Button.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Shift}" Value="True">
<Setter Property="Control.Background" Value="Black">
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I'll appreciate all help I can get.
Thanks,
Stefan

You are right.You can do it with datatriggers.You need to set the datacontext of the widow to this for this to work.Otherwise the binding will not be able to access your dependency property.
public VirtualKeyboard()
{
InitializeComponent();
DataContext = this;
}
and specify your style like
<Button Grid.Column="0" Content="Shift" Name="ShiftButton">
<Button.Style>
<Style>
<Setter Property="Button.Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Shift}" Value="True">
<Setter Property="Button.Visibility" Value="Visible">
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>

Related

Switch images with a data template

I know that already some questions exist but I can not fix my problem with them.
Problem: I try to change a image with a data template but just the default image is visible.
Code:
My xaml code is like this:
<Window.Resources>
<DataTemplate x:Key="MultiTemplate">
<Image Height="17" Width="17">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="{svg2Xaml:SvgImage VideoControllerTester;component/Resources/Start.svg}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding MultiTrigger}" Value="start">
<Setter Property="Source" Value="{svg2Xaml:SvgImage VideoControllerTester;component/Resources/Start.svg}"/>
</DataTrigger>
<DataTrigger Binding="{Binding MultiTrigger}" Value="stop">
<Setter Property="Source" Value="{svg2Xaml:SvgImage VideoControllerTester;component/Resources/Stop.svg}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</DataTemplate>
</Window.Resources>
<ContentControl ContentTemplate="{DynamicResource MultiTemplate}"/>
In the code behind I set MultiTrigger = "start" or "stop".
Question: Can I show the images with the content control? Or I do some dumb stuff with the data template?
Edit:
public string MultiTrigger
{
get { return _multiTrigger; }
set
{
_multiTrigger = value;
RaisePropertyChanged();
}
}
Assuming that there is a MainViewModel class with a MultiTrigger property (which btw. is a strange property name), you would assign an instance of the view model class to the MainWindow's DataContext, either in code behind:
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
Or in XAML:
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
Then you would declare the Image Style as a resource:
<Window.Resources>
<Style TargetType="Image" x:Key="ImageStyle">
<Setter Property="Source" Value="{svg2Xaml:SvgImage VideoControllerTester;component/Resources/Start.svg}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding MultiTrigger}" Value="stop">
<Setter Property="Source" Value="{svg2Xaml:SvgImage VideoControllerTester;component/Resources/Stop.svg}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
and apply it to an Image control:
<Image Style="{StaticResource ImageStyle}"/>
Then change the property value somewhere in the MainWindow's code behind by directly accessing the view model instance like this:
((MainViewModel)DataContext).MultiTrigger = "stop";

How to bind data from View to ViewModel?

I have little knowledge about mvvm, but this is how I wrote my code this far:
<Image x:Name ="new_tooltip" Grid.Row="84" Grid.Column="57" Grid.ColumnSpan="78" Grid.RowSpan="15" Source="/MS_Show_Assets/MainMenuAssets/TT-Startscreen-MainMenu-New-DE.png" Visibility = "{Binding IsMouseOver, ElementName=New, Converter={StaticResource BooleanToVisibilityConverter}}">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Visibility" Value="{Binding Path=IsNewTooltipVisible, Mode=OneWayToSource}" />
</Style>
</Image.Style>
</Image>
and ViewModel:
public class ViewMainMenuViewModel : BindableBase
{
public string IsNewTooltipVisible { get; set; }
public ViewMainMenuViewModel()
{
}
}
So basically, I want some image in the view to become visible if the mouse is over some button. Then once this image is visible, I want to send "Visible" to a property that is in ViewModel class. What else am I missing in this class?
you dont need a property in VM to do this. You can use Trigger on View itself to show/hide image on button mouseover as below. Here ElementName is the name of the button whose mouseover you want to capture.
<Image x:Name ="new_tooltip" Grid.Row="84" Grid.Column="57" Grid.ColumnSpan="78" Grid.RowSpan="15" Source="/MS_Show_Assets/MainMenuAssets/TT-Startscreen-MainMenu-New-DE.png" Visibility = "{Binding IsMouseOver, ElementName=New, Converter={StaticResource BooleanToVisibilityConverter}}">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Visibility" Value="Collapsed"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, ElementName=myButton}" Value="true">
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>

Image Data triggers not working

I have bindings for images in listviews that work fine with boolean conditions. I have created a custom property PlotSettingsFileExists, and an image on a usercontrol but nothing seems to show at runtime.
public partial class BatchDialogUC : UserControl
{
public bool PlotSettingsFileExists
{
get { return File.Exists(Strada.Settings.PlotTemplateFile); }
}
}
<Image Name="imgPltSettings" Width="16" Height="16">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding PlotSettingsFileExists}" Value="true">
<Setter Property="Source" Value="/StradaRPC;component/Resources/imgDrawing.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding PlotSettingsFileExists}" Value="false">
<Setter Property="Source" Value="/StradaRPC;component/Resources/ExlamationMark.png"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
Does anyone have any suggestions on this?
Looks you have PlotSettingsFileExists property inside your view, but it should be defined in viewmodel and set viewmodel as datacontext of your usecontrol
just set the DataContext. public BatchDialogUC() { InitializeComponent(); DataContext = this; } – Ram Nivas

Resource 1 works, 2 doesn't

<ToggleButton Command="{Binding Path=Command}" Content="{Binding Path=DisplayName}" Template="{Utilities:BindableResource {Binding Path=TemplateResource}}">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Template" Value="{Utilities:BindableResource {Binding Path=SelectedTemplateResource}}" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
The first bindable resource works for "TemplateResource" on the template property of togglebutton however "SelectedTemplateResource" does not work within the tiggers setter. This code is within a resourcedictionary where the actual resource is within a themed resourcedictionary.
I get an error saying key is null for xamlparseexception for the setter value. I've been stairing at this for hours but cannot figure out why it doesn't work... If I take out the style and replace the first binding with the second resource it does display proper however the binding within the style will not work.
Does anybody have any idea why?
EDIT
I just tried this but no luck.
<ToggleButton Command="{Binding Path=Command}" Content="{Binding Path=DisplayName}">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Style.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Template" Value="{Utilities:BindableResource {Binding Path=TemplateResource}}" />
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Template" Value="{Utilities:BindableResource {Binding Path=SelectedTemplateResource}}" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
After finding out this really is not possible to do in pure xaml I brought out the c# and create a custom control... this is very basic and can be improved on and I will have change a bit of it but ultimately a custom control solves the issue so that you can hit the click event from within the resource dictionary and change the template on the fly.
public class TabButton : Button
{
public static readonly DependencyProperty SelectedTemplateProperty =
DependencyProperty.Register("SelectedTemplate", typeof(ControlTemplate), typeof(TabButton));
public ControlTemplate SelectedTemplate
{
get { return base.GetValue(SelectedTemplateProperty) as ControlTemplate; }
set { base.SetValue(SelectedTemplateProperty, value); }
}
public TabButton()
{
this.Click += new RoutedEventHandler(TabButton_Click);
}
~TabButton()
{
}
public void TabButton_Click(object sender, RoutedEventArgs e)
{
ControlTemplate template = (ControlTemplate)this.FindResource("Environmental Template Selected");
(sender as TabButton).Template = template;
}
}
Cheers.

Using custom dependency properties as DataTrigger in WPF

I have a custom dependency property that I would like to use as a data trigger. Here is the code behind:
public static readonly DependencyProperty BioinsulatorScannedProperty =
DependencyProperty.Register(
"BioinsulatorScanned",
typeof(bool),
typeof(DisposablesDisplay),
new FrameworkPropertyMetadata(false));
public bool BioinsulatorScanned
{
get
{
return (bool)GetValue(BioinsulatorScannedProperty);
}
set
{
SetValue(BioinsulatorScannedProperty, value);
}
}
I have created a style and control template. My goal is to change the color of some text when the dependency prop is set to true...
<Style x:Key="TreatEye" TargetType="Label">
<Setter Property="Foreground" Value="#d1d1d1" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontSize" Value="30" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<Canvas>
<TextBlock x:Name="bioinsulatorText"
Canvas.Left="21" Canvas.Top="33"
Text="Bioinsulator" />
<TextBlock Canvas.Left="21" Canvas.Top="70"
Text="KXL Kit" />
</Canvas>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding BioinsulatorScanned}"
Value="True">
<Setter TargetName="bioinsulatorText"
Property="Foreground" Value="Black" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Despite successfully setting the dependency prop to true programmatically, This trigger condition never fires. This is a real pain to debug!
Thanks in advance.
In this case I am switching the visibility of a button using a datatrigger based on a dependency property FirstLevelProperty.
public static readonly DependencyProperty FirstLevelProperty = DependencyProperty.Register("FirstLevel", typeof(string), typeof(MyWindowClass));
public string FirstLevel
{
get
{
return this.GetValue(FirstLevelProperty).ToString();
}
set
{
this.SetValue(FirstLevelProperty, value);
}
}
You can reference the dependency property FirstLevel(Property) contained (in this case) in a window by using the RelativeSource binding. Also you should set the default setting in the style, that will be overridden by the datatrigger.
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger
Binding="{Binding Path=FirstLevel,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}}"
Value="SomeValue">
<Setter Property="Visibility"
Value="Hidden" />
</DataTrigger>
</Style.Triggers>
<Setter Property="Visibility" Value="Visible" />
</Style>
</Button.Style>
It looks like your dependency property is defined inside a DisposableDisplay object that you created. In order for the binding specified to work, an instance of that DisposableDisplay object must be set as the DataContext of the control (label in this case) or any of its ancestors.

Resources