Window ResizeMode bind to Settings - c#

I would like to permit the user to change the Window ResizeMode property, set by default in my case to ResizeMode="CanMinimize". How could it be switched to ResizeMode="CanResize"?
I think it could be done by creating a Boolean (or a CheckBox.IsChecked property) bound to ResizeMode with a converter, but I'm not sure if that's the way. Even if it was the right option I don't know how to create a converter that converts "True" to "CanResize" and "False" to "CanMinimize".

I prefer a Trigger solution
<Window>
<CheckBox Name="checkbox" Content="CanResize" />
<Window.Style>
<Style TargetType="Window">
<Setter Property="ResizeMode" Value="CanMinimize" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=checkbox}" Value="True">
<Setter Property="ResizeMode" Value="CanResize" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Style>
</Window>

Creating a converter is pretty simple right.
Have something like:
using System.Globalization;
using System.Windows;
using System.Windows.Data;
public class ResizeModeConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
return (bool)value ? ResizeMode.CanResize : ResizeMode.CanMinimize;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
and add this converter to your App.xaml Resources(Converter should be in a scope available to your Window)
<Application.Resources>
<local:ResizeModeConverter x:Key="ResizeModeConverter" />
</Application.Resources>
Now in your Window
<Window ... ResizeMode="{Binding SomeProperty, Converter={StaticResource ResizeModeConverter}}">
Now when SomeProperty is set to true or false you get your required behavior. You can set the property in your VM at startup after reading your local setting's or modify it at runtime and everything should be fine.

Related

WPF SVG image binding using a converter

I would like to change my image source from:
<Image Source="{svg:SvgImage image.svg}"/>
To something that use binding on an enum property instead:
XAML:
<Resources>
<local:MyConverter x:Key="MyConverter" />
</Resources>
<Image Source="{svg:SvgImage Binding MyEnumProperty, Converter={StaticResource MyConverter}}" />
Code behind:
public enum MyEnum
{
Value1,
Value2
}
public class MyConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var myValue = (MyEnum)(value);
switch (myValue)
{
case MyEnum.Value1:
return "image1.svg";
case MyEnum.Value2:
return "image2.svg";
default:
throw new NotImplementedException();
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
This doesn't work and I suspect that is has something to do with the svg:SvgImage and Binding MyEnumProperty being combined in the same statement.
I get the following errors:
The member "Converter" is not recognized or is not accessible.
And
The property 'Converter' was not found in type 'SvgImageExtension'.
Question:
What is the correct way to do this?
The expression
{svg:SvgImage Binding MyEnumProperty ...}
is not valid XAML, and because SvgImage is a markup extension, you can't bind its properties.
You may however use DataTriggers in an Image Style instead of a Binding with a Converter:
<Image>
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding MyEnumProperty}" Value="Value1">
<Setter Property="Source" Value="{svg:SvgImage image1.svg}"/>
</DataTrigger>
<DataTrigger Binding="{Binding MyEnumProperty}" Value="Value2">
<Setter Property="Source" Value="{svg:SvgImage image2.svg}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>

Style object based on binding bool attribute in wpf

How can change the fill color of an object I'm being to in my mvvm setup using xaml in wpf. I want to change the fill color to red when the attribute being bound to is set to True.
The attribute is called IsRound.
I'll post code if necessary. I'm not on a pc at the moment.
UPDATED
Could someone show an example of how to do this using style triggers?
And set the value based on the bind property bool?
First of all you don't need any Binding for what you are trying to do. DataTrigger is enough. In the example below IsCyan is a boolean property of ViewModel. But Background of TextBlock is not bound at all.
<TextBlock Text="Inside content">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding IsCyan}" Value="True">
<Setter Property="Background" Value="DarkCyan"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsCyan}" Value="False">
<Setter Property="Background" Value="DarkGoldenrod"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
But if at all you need Binding, solution by the user benPearce to use Converter is the way to go.
You need to use an IValueConverter on the binding.
BackgroundColor="{Binding Path=IsRound, Converter={StaticResource BoolToFillColorConverter}}"
public class BoolToFillColorConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool b;
if (bool.TryParse(value, out b))
{
if (b) return Red
else return Blue;
}
else
{
return SomeDefaultColour;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}

Storing information in ViewModel or using IValueConverter

If I want to change the Background-color of a Button in wpf to red, if the property Amount in my view model is 0 and to green if it is greater than 0, is it better to use a value converter for this, or should I simply implement a custom Background-property in my view model? This Background-property would wrap the Amount-value to a SolidColorBrush, which will be bound to the Background of the Button.
Which way is more straight forward?
Thank you!
I would use a DataTrigger.
Apply the following style to your button.
It has a binding to the Amount property in your view model.
It sets the default background color to 'green' and changes to 'red' if the value of Amount is 0.
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Green" />
<Style.Triggers>
<DataTrigger Binding="{Binding Amount}" Value="0">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
Additional info
You can also check for more than one codition using a MultiDataTrigger.
It looks like this:
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{...}, Value="..."/>
<Condition Binding="{...}, Value="..."/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="A" Value="..."/>
<Setter Property="B" Value="..."/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
Check out this article on how to use it.
It seems that for range checking you would need to implement a IValueConverter like mentioned in the other responses or in this answer.
I would do it with Trigger, but Converter is Ok too. But I definitely won't make property Background in ViewModel, because Background is about design, about view so it is better to define it in View
I'd make bool property in viewmodel, which is calculated when Amount is changed:
public bool IsAmountZero
{
get { return Amount == 0; }
}
private int _amount;
public int Amount
{
get { return _amount; }
set
{
_amount = value;
OnPropertyChanged();
OnPropertyChanged(nameof(IsAmountZero));
}
}
And then write converter BoolToColorConverter (where colors could be via ConverterParameter somehow).
// in current form it's actually BoolToColorRedGreenConverter
public class BoolToColorConverter : MarkupExtension, IValueConverter
{
public BoolToColorConverter() { }
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool)
{
var colorFalse = Colors.Green;
var colorTrue = Colors.Red;
if (parameter != null)
{
//...
}
return (bool)value ? colorTrue : colorFalse;
}
throw new InvalidCastException();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
use it like this
<Button.Background>
<SolidColorBrush Color="{Binding IsAmountZero, Converter={local:BoolToColorConverter}}" />
</Button.Background>
This would be quite reusable solution.
Otherwise just make converter IntZeroCheckToColorGreenRedConverter, but it will not be very reusable compared to one with bool property.
Idea with Brush property in view model is bad, because viewmodel doesn't realy care about colors. Viewmodel should only contain logic related to model which is then used by view. If you want to simply change color (e.g use Blue instead of Green) - this change has to be done in the view. Therefore bool property and BoolToColorConverter (or BoolToSolidBrushConverter to use directly with Background attribute in xaml) converters.
Setting the Button's background is something view's related i don't thing that setting it from the ViewModel is a good idea, i think that it is much better if you define the Amount property in the ViewModel, define a DataTrigger to check the amount value Against the 0 using a Converter
<Window.Resources>
<YurNs:GreaterThanValConverter x:Key="GreaterThanValConverter"/>
</Window.Resources>
<StackPanel>
<TextBox Text="{Binding Amount,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Button">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Green"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Amount,Converter={StaticResource GreaterThanValConverter}}" Value="false">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
and the converter
public class GreaterThanValConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int) value > 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
One more thing you may as well consider passing a parameter to the converter to compare against so that your solution would be as customizable as possible.

Show alternating images for changing ViewModel states

For different user interfaces I want to show an image depending on a state of a ViewModel object.
For example:
I have a database connection, if connected, I want to show a green database image, if not connected I want to display a red database image.
In the ViewModel there is a bool that represents the state.
Possibilities are:
Having two images in the view (with a converter InverseBooleanToVisibilityConverter for the red image), which are at the same place, actually just showing one of them.
Binding for Image source (but I do not want to set this in my ViewModel)
Some sort of selector?
This state depending image can be more often of use, e.g. in a TreeView as ItemImage.
Is there a more clever way to accomplish that?
You can also do it with solely with data triggers. Here's a sample from one of my projects for a button that changes it's image depending on whether or not the form is in an Edit mode or not:
<Button x:Name="EditOrSaveJob"
Width="32"
Height="32"
Margin="10,0,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Image>
<Image.Style>
<Style TargetType="Image">
<Setter Property="Source" Value="/AAAA;component/Resources/Images/edit.png" />
<Setter Property="ToolTip" Value="Edit Order" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsEditing}" Value="True">
<Setter Property="Source" Value="/AAAA;component/Resources/Images/32_save.png" />
<Setter Property="ToolTip" Value="Save Order" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Button>
I use a valueconverter like so:
public class BoolToImageConverter: DependencyObject, IValueConverter
{
public BitmapImage TrueImage
{
get { return (BitmapImage)GetValue(TrueImageProperty); }
set { SetValue(TrueImageProperty, value); }
}
public static DependencyProperty TrueImageProperty = DependencyProperty.Register("TrueImage", typeof(BitmapImage), typeof(BoolToImageConverter), null);
public BitmapImage FalseImage
{
get { return (BitmapImage)GetValue(FalseImageProperty); }
set { SetValue(FalseImageProperty, value); }
}
public static DependencyProperty FalseImageProperty = DependencyProperty.Register("FalseImage", typeof(BitmapImage), typeof(BoolToImageConverter), null);
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (bool)value ? TrueImage : FalseImage;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var img = (BitmapImage)value;
return img.UriSource.AbsoluteUri == TrueImage.UriSource.AbsoluteUri;
}
}
and in XAML
<my:BoolToImageConverter x:Key="converterName" FalseImage="{StaticResource falseImage}" TrueImage="{StaticResource trueImage}"/>
The solution would be using converter (class that implements IValueConverter):
class ImageStateConverter : IValueConverter
{
public Object Convert( Object value, Type targetType, Object parameter, CultureInfo culture)
{
bool state = (bool) value;
return state ? "img1.png" : "img2.png";
}
}
Then in your XAML write binding like this:
<Image Source="{Binding Path=State, Converter={StaticResource myConverter}}" />
Object myConverter is declared somewhere in Resources section.

WPF Trigger that would work if the value is equal or greater

I wrote an application in WPF that has a button and slider. I would like to create a trigger for the button, which would set the button's 'IsEnable' property to false when the slider value is greater than another value.
Right now I have:
<Style x:Key="zoomOutButton" TargetType="Button" BasedOn="{StaticResource ResourceKey=buttonStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentAltitude}" Value="24000">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
But I would like to set isEnable not when the value of CurrentAltitude equal 24000, but when it is equal or greater than 24000.
Any ideas?
You can achieve this using a converter:
public class IsEqualOrGreaterThanConverter : IValueConverter {
public static readonly IValueConverter Instance = new IsEqualOrGreaterThanConverter();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
int intValue = (int) value;
int compareToValue = (int) parameter;
return intValue >= compareToValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
Then your trigger will look like this:
<Style x:Key="zoomOutButton" TargetType="Button" BasedOn="{StaticResource ResourceKey=buttonStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentAltitude, Converter={x:Static my:IsEqualOrGreaterThanConverter.Instance}, ConverterParameter=24000}" Value="True">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
A more generic converter, usable with any comparable type, could be :
public class IsGreaterOrEqualThanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
IComparable v = value as IComparable;
IComparable p = parameter as IComparable;
if (v == null || p == null)
throw new FormatException("to use this converter, value and parameter shall inherit from IComparable");
return (v.CompareTo(p) >= 0);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
But in this case, the ConverterParameter must be interpreted with the same type as the value transmitted to your Converter. For example, to compare an int property 'MyIntProperty' with the contant int value 1, in your XAML, you can use this syntax :
<UserControl x:Class="MyNamespace.MyControl"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:genconverters="clr-namespace:MyConverterNamespace;assembly=MyConvertersAssembly">
<Grid>
<Grid.Resources>
<genconverters:IsGreaterOrEqualThanConverter x:Key="IsEqualOrGreaterThanConverter"/>
<sys:Int32 x:Key="Int1">1</sys:Int32>
</Grid.Resources>
<ComboBox IsEnabled="{Binding MyIntProperty,
Converter={StaticResource IsEqualOrGreaterThanConverter},
ConverterParameter={StaticResource Int1}}"
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}"/>
</Grid>

Categories