Switch images with a data template - wpf

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";

Related

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

INotifyPropertyChange ignored in binding to a DataTrigger

I'm working on some code that has a Button that contains an image and some text, and which should display either the image, the text, or both, depending upon the value of a bound property. The code is currently using Styles and DataTriggers:
public enum ButtonStyle { Image, Text, Both };
public class ViewModel : INotifyPropertyChanged
{
private ButtonStyle _buttonStyle;
public ButtonStyle buttonStyle
{
get { return this._buttonStyle; }
set
{
this._buttonStyle = value;
notifyPropertyChanged("buttonStyle");
}
}
And:
<UserControl.Resources>
<Style x:Key="buttonTextStyle" TargetType="{x:Type Label}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=buttonStyle}"
Value="{x:Static local:ButtonStyle.Text}">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="buttonImageStyle" TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=buttonStyle}"
Value="{x:Static local:ButtonStyle.Image}">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Button>
<StackPanel>
<Image Source="..." Style="{StaticResource buttonImageStyle} />
<Label Style={StaticResource buttonTextStyle}>My Text</Label>
</StackPanel>
</Button>
My problem? The button doesn't change when I change the value of the buttonStyle property in the view model. This control is in a tab, and if I switch to another tab and then switch back, the button updates to reflect the current value of the buttonStyle property, but it does not change until I do.
It looks like the DataTrigger is processed only when the control is rendered, and does not re-render when the bound value is modified, despite the bound value raising a PropertyChanged event.
Any ideas?
Try NotifyOnSourceUpdated=True on each of your data triggers.
<DataTrigger Binding="{Binding Path=buttonStyle, NotifyOnSourceUpdated=True}"
Value="{x:Static local:ButtonStyle.Text}">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
I think this is a nicer way to refer to enums in your DataTrigger:
<Style x:Key="buttonImageStyle" TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=buttonStyle}">
<DataTrigger.Value>
<local:ButtonStyle>Text</local:ButtonStyle>
</DataTrigger.Value>
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
The value of the resource changes during runtime, thats why you should use DynamicResource instead of StaticResource:
Style="{DynamicResource buttonImageStyle}"
Here's an idea - any time you have a binding problem and it looks like INotifyPropertyChanged isn't working, check and double check and make damned sure that you spelled the name of the property right, in your PropertyChangedEventArgs().
Sorry for the trouble.

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>

Conditionals in WPF

I have the following question: I have a Boolean variable in a configuration file. If it is true I want a property in textbox control to be setup according to the value of that variable.
Try the solution above but it does not work. What am I doing wrong?
This is a fragment code:
bool isKeyboardAvtive = true; //read from configuration file
<Style x:Key="StylesTextBox" TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=isKeyboardActive}" Value="True">
<Setter Property="k:TouchScreenKeyboard.TouchScreenKeyboard" Value="True"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=isKyboardActive}" Value="False">
<Setter Property="k:TouchScreenKeyboard.TouchScreenKeyboard" Value="False"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<TextBox Style="{StaticResource StylesTextBox}" Margin="0,5" x:Name="txtUserName" Height="40" Width="150" />
IsKeyboardActive needs to be a public property of the DataContext for the binding to work. Also, you don't need a trigger there, just a binding :
k:TouchScreenKeyboard.TouchScreenKeyboard="{Binding IsKeyBoardActive}"
If you use the standard VS-generated settings, you can also bind to the settings directly :
xmlns:prop="clr-namespace:YourApplication.Properties"
...
k:TouchScreenKeyboard.TouchScreenKeyboard="{Binding IsKeyBoardActive, Source={x:Static prop:Settings.Default}}"
Or even better, using this markup extension :
xmlns:local="clr-namespace:YourApplication"
...
k:TouchScreenKeyboard.TouchScreenKeyboard="{local:SettingBinding IsKeyBoardActive}"

Resources