Image Data triggers not working - wpf

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

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>

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.

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>

'View cannot be shared by more than one ListView' Wpf Error

What is wrong with this code ? It throws the Exception: "View cannot be shared by more than one ListView"
<ListView
ItemsSource="{Binding}"
SelectionMode="Extended">
<ListView.Style>
<Style TargetType="ListView">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MyControl, Path=IsCompany}" Value="True">
<Setter Property="View" Value="{StaticResource GridViewCompanies}" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=MyControl, Path=IsCompany}" Value="False">
<Setter Property="View" Value="{StaticResource GridViewPeople}" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=MyControl, Path=IsCompany}" Value="{x:Null}">
<Setter Property="View" Value="{StaticResource GridViewBoth}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Style>
</ListView>
public bool? IsCompany
{
get { return (bool?)GetValue(IsCompanyProperty); }
set { SetValue(IsCompanyProperty, value); }
}
public static readonly DependencyProperty IsCompanyProperty =
DependencyProperty.Register("IsCompany", typeof(bool?), typeof(MyControl), new UIPropertyMetadata(null));
EDITED:
I've tried to set the View in code behind and it works. What's the problem with XAML then?
if() ..
MyListView.View = Resources["GridViewCompanies"] as GridView;
The error is because the GridView is being applied to more than one ListView. Is your ListView Style being applied to more than one control? I took a look in Reflector, and it looks like this scenario should work for a single control.
What exactly are you trying to accomplish? I imagine you just want to show different columns. Maybe you can create an attached behavior to generate columns for the GridView depending on the value of the property you are binding to.

Resources