Resource 1 works, 2 doesn't - wpf

<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.

Related

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

how to create a generic background image binding from a control template?

i have button with this style:
<Style TargetType="Button" x:Key="btnStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Image x:Name="img" Source="{TemplateBinding Tag}" Margin="{TemplateBinding Margin}"
Stretch="None"></Image>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="img" Property="Source" Value="{DynamicResource imgClose_P}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="img" Property="Source" Value="{DynamicResource imgClose_H}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
As you can see i'm binding the ImageSource to the Tag property of the button.
And in the Tag property i'm binding it to a ResourceDictionary that store this bitmap:
<BitmapImage x:Key="imgClose_N" UriSource="..\AppImages\mainWindow\TopBanner\CloseButton_sN.png" />
this gives me the ability to use this "Imagebutton" all over the application with different background images and one template.
the problem is how to keep this generic approach with triggers?
i would like the IsMouseOver trigger to change the background image but to bind it to some property of the control and not to write it hard coded in the control template.
how can this be done ?
As you already suggest by calling it an "Imagebutton", you may derive from Button and define some image properties to bind to, e.g. BackgroundImage, MouseOverImage, etc.
An alternative to deriving from Button would be to use attached properties to set the images and bind to those in your style, but these attached properties would also have to be defined somewhere, which doesn't make it simpler.
Here's an example for the first solution:
public class ImageButton : Button
{
public static readonly DependencyProperty NormalBackgroundImageProperty = DependencyProperty.Register(
"NormalBackgroundImage", typeof(ImageSource), typeof(ImageButton));
public static readonly DependencyProperty MouseOverBackgroundImageProperty = DependencyProperty.Register(
"MouseOverBackgroundImage", typeof(ImageSource), typeof(ImageButton));
public static readonly DependencyProperty PressedBackgroundImageProperty = DependencyProperty.Register(
"PressedBackgroundImage", typeof(ImageSource), typeof(ImageButton));
public ImageSource NormalBackgroundImage
{
get { return (ImageSource)GetValue(NormalBackgroundImageProperty); }
set { SetValue(NormalBackgroundImageProperty, value); }
}
public ImageSource MouseOverBackgroundImage
{
get { return (ImageSource)GetValue(MouseOverBackgroundImageProperty); }
set { SetValue(MouseOverBackgroundImageProperty, value); }
}
public ImageSource PressedBackgroundImage
{
get { return (ImageSource)GetValue(PressedBackgroundImageProperty); }
set { SetValue(PressedBackgroundImageProperty, value); }
}
}
and an appropriate style below. Note that this style also has a ContentPresenter for the button's content, and that it uses regular bindings with RelativeSource={RelativeSource TemplatedParent} instead of TemplateBindings. These are evaluated at runtime.
<Style TargetType="local:ImageButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:ImageButton">
<Grid Margin="{TemplateBinding Margin}">
<Image x:Name="img" Source="{Binding NormalBackgroundImage, RelativeSource={RelativeSource TemplatedParent}}" Stretch="None"/>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="img" Property="Source" Value="{Binding MouseOverBackgroundImage, RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="img" Property="Source" Value="{Binding PressedBackgroundImage, RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You would have to define or replace the XAML namespace local with a mapping to the namespace/assembly that contains the class ImageButton.
The button could then be use like this:
<local:ImageButton
Margin="10"
NormalBackgroundImage="C:\Users\Public\Pictures\Sample Pictures\Desert.jpg"
PressedBackgroundImage="C:\Users\Public\Pictures\Sample Pictures\Tulips.jpg"
MouseOverBackgroundImage="C:\Users\Public\Pictures\Sample Pictures\Penguins.jpg"
Content="Click Me"/>

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

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>

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.

WPF: Is it standard that when a menuitem is disabled the icon is not greyed out?

I have menuitems with icons and when it is disabled the icon remains the same. Is it up to me to supply a disabled icon and, if so, does this also apply to menuitems bound to a command?
Found Jobi's answer helpful. Here's another way to accomplish the same thing using an Image Style and the MenuItem.Icon:
<MenuItem Header="Add ..." Command="{Binding AddCommand}" >
<MenuItem.Icon>
<Image Source="{StaticResource AddImage}" Style="{StaticResource EnableDisableImageStyle}"/>
</MenuItem.Icon>
</MenuItem>
And the Style:
<Style x:Key="EnableDisableImageStyle" TargetType="{x:Type Image}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.75"/>
<Setter Property="BitmapEffect">
<Setter.Value>
<BlurBitmapEffect Radius="2.0" KernelType="Gaussian"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Yes it is totally up to you. Because you have provided an Icon file. So you need to create Style.Trigger on MenuItem to give disabled effect on that. Either do a Opacity =0.5 or switch image to a different .ico image while IsEnabled=False in the template
Actually I had the same problem and and I could not find a satisfying answer to this question. Changing the opacity is quite simple, but what if you want to change the complete appearance of an Icon for a MenuItem. It took me two days to find a simple solution. Since I am pretty new to WPF I had to read through different concepts and Attached Properties was one that got me to my solution. Here is my code for changing the Icon depending on enabled/disabled MenuItem:
Here is the code, which defines the Attached Properties used by the style setter:
public static class AltImageProvider
{
public static string GetAltImage(DependencyObject obj)
{
return (string)obj.GetValue(AltImageProperty);
}
public static void SetAltImage(DependencyObject obj, string value)
{
obj.SetValue(AltImageProperty, value);
}
public static readonly DependencyProperty AltImageProperty =
DependencyProperty.RegisterAttached("AltImage",typeof(string),typeof(AltImageProvider));
public static string GetDefImage(DependencyObject obj)
{
return (string)obj.GetValue(DefImageProperty);
}
public static void SetDefImage(DependencyObject obj, string value)
{
obj.SetValue(DefImageProperty, value);
}
public static readonly DependencyProperty DefImageProperty =
DependencyProperty.RegisterAttached("DefImage",typeof(string),typeof(AltImageProvider));
}
Here is the code defining a style for Images like the Icons, that uses the Attached Properties (DefImage and AltImage):
<Style x:Key="ImageDisableAltImageStyle" TargetType="Image">
<Setter Property="Image.Source" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(local:AltImageProvider.DefImage)}"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Image.Source" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(local:AltImageProvider.AltImage)}"/>
</Trigger>
</Style.Triggers>
</Style>
Here is how to set the style and Icons for a MenuItem:
<MenuItem.Icon>
<Image Style="{StaticResource ImageDisableAltImageStyle}" local:AltImageProvider.DefImage="/Icon/play_green.ico" local:AltImageProvider.AltImage="/Icon/play_grey.ico"/>
</MenuItem.Icon>
This seems odd, but all I did was create the following style. You'd think this is the built in behavior, but without this (like the OP), the image isn't dimmed. With this, the image is affected, too. And I don't need to modify anything else in my app.
<Style TargetType="MenuItem">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5"/>
</Trigger>
</Style.Triggers>
</Style>
This targets only the icons on all MenuItems, without needing any keys and without affecting the look of the menu text.
<Style TargetType="MenuItem">
<Style.Resources>
<!-- Replace Frame with the actual icon container, e.g. Image -->
<Style TargetType="Frame">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5"/>
</Trigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>

Resources