I want when visibility of "StckPnl1" is set to Collapsed, my property "IsBusyIndicatorShowing" of "BusyDeco1" is being set to true.
What's the simplest solution?
<ctrls:BusyDecorator x:Name="BusyDeco1" IsBusyIndicatorShowing="??" Style="{DynamicResource BusyDecorator1}"/>
<StackPanel x:Name="StckPnl1" Visibility="Collapsed">
Use a DataTrigger:
<ctrls:BusyDecorator>
<ctrls:BusyDecorator.Style>
<Style TargetType="{x:Type ctrls:BusyDecorator}" BasedOn="{DynamicResource BusyDecorator1}">
<Setter Property="IsBusyIndicatorShowing" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=StckPnl1, Path=Visibility}" Value="Collapsed">
<Setter Property="IsBusyIndicatorShowing" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</ctrls:BusyDecorator.Style>
</ctrls:BusyDecorator>
i use a converter for this stuff.
<ctrls:BusyDecorator x:Name="BusyDeco1"
IsBusyIndicatorShowing="{Binding ElementName=StckPnl1, Path=Visibility, Converter={StaticResource TrueIfNotVisibleConverter}}" Style="{DynamicResource BusyDecorator1}"/>
<StackPanel x:Name="StckPnl1" Visibility="Collapsed">
<Converter:BoolToVisibilityConverter x:Key="TrueIfVisibleConverter" Inverted="False" Not="False" />
<Converter:BoolToVisibilityConverter x:Key="TrueIfNotVisibleConverter" Inverted="False" Not="True" />
<Converter:BoolToVisibilityConverter x:Key="VisibleIfTrueConverter" Inverted="True" Not="False" />
<Converter:BoolToVisibilityConverter x:Key="VisibleIfNotTrueConverter" Inverted="True" Not="True" />
public class BoolToVisibilityConverter : IValueConverter
{
private bool inverted = false;
private bool not = false;
public bool Inverted
{
get { return inverted; }
set { inverted = value; }
}
public bool Not
{
get { return not; }
set { not = value; }
}
private object VisibilityToBool(object value)
{
if (!(value is Visibility))
return DependencyProperty.UnsetValue;
return (((Visibility)value) == Visibility.Visible) ^ Not;
}
private object BoolToVisibility(object value, object parameter)
{
if (!(value is bool))
return DependencyProperty.UnsetValue;
var hiddenodercollapsed = Visibility.Collapsed;
if (parameter != null && parameter.ToString().ToLower().Contains("hidden"))
hiddenodercollapsed = Visibility.Hidden;
return ((bool)value ^ Not) ? Visibility.Visible : hiddenodercollapsed;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Inverted ? BoolToVisibility(value, parameter) : VisibilityToBool(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Inverted ? VisibilityToBool(value) : BoolToVisibility(value, parameter);
}
}
Related
I have a xamDataGrid where I read in data from a file. This field is of type datetime. I would like to change the foreground color of this column when the date loaded is greater than todays date. I have a following IValueConverter:
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
{
var color = new SolidColorBrush(Colors.Red);
int result = DateTime.Compare((DateTime)value, todaysDate);
if (result > 0)
return color = new SolidColorBrush(Colors.Red);
else
return color = new SolidColorBrush(Colors.White);
}
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I get and error from this: (DateTime)value
When I step through the code it seems that the if (value !=null) is executed even though there is no data being displayed in the datagrid. Not sure why this is in this path. It should only be executed when I'm loading a file into the datagrid.
Here is the xaml:
<viewModel:MyConverter x:Key="myDateConv"/>
<igDP:UnboundField Name="My Date" BindingPath="MyDate" Width="Auto" BindingMode="TwoWay" >
<igDP:UnboundField.Settings>
<igDP:FieldSettings AllowEdit="True" >
<igDP:FieldSettings.EditorStyle>
<Style TargetType="{x:Type igEditors:XamDateTimeEditor}" >
<Setter Property="Mask" Value="mm/dd/yyyy" />
<Setter Property="Foreground" Value="{Binding RelativeSource={x:Static RelativeSource.Self},Converter={StaticResource myDateConv}}"/>
</Style>
</igDP:FieldSettings.EditorStyle>
</igDP:FieldSettings>
</igDP:UnboundField.Settings>
</igDP:UnboundField>
here is the class:
public class myPrice : INotifyPropertyChanged
{
private DateTime myDate;
public DateTime MyDate
{
get { return myDate; }
set
{
if (myDate != value)
{
priceDate = value;
NotifyPropertyChanged("MyDate");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
I have a custom ComboBox with this definition.
<UserControl ...>
<Grid>
<Grid.Resources>
<local:InheritanceEnumValueConverter x:Key="inheritanceEnumValueConverter"/>
</Grid.Resources>
<samples:MaterialEnumComboBox x:Name="materialComboBoxGenerateStatements"
Grid.Column="3" Grid.Row="1" Height="30" Width="120"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
IsEditable="True" IsReadOnly="True"
EnumSource="enums:YesNoInherit" Margin="52,0">
<samples:MaterialEnumComboBox.Style>
<Style TargetType="samples:MaterialEnumComboBox">
<Setter Property="Text"
Value="{Binding Path=selectedModel.GenerateStatements,
UpdateSourceTrigger=PropertyChanged}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding selectedModel.GenerateStatements}">
<DataTrigger.Value>
<enums:YesNoInherit>Inherit</enums:YesNoInherit>
</DataTrigger.Value>
<Setter Property="Text">
<Setter.Value>
<MultiBinding Converter="{StaticResource inheritanceEnumValueConverter}">
<Binding Path="selectedModel.GenerateStatements"></Binding>
<Binding Path="selectedModel.DefaultGenerateStatements"></Binding>
</MultiBinding>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</samples:MaterialEnumComboBox.Style>
</samples:MaterialEnumComboBox>
</Grid>
</UserControl>
Here is the custom ComboBox. There is no significant XAML.
public partial class MaterialEnumComboBox
{
private Type _enumSource;
public Type EnumSource
{
get { return _enumSource; }
set
{
_enumSource = value;
this.SetBinding(ItemsSourceProperty, new Binding { Source = Enum.GetValues(_enumSource) });
}
}
public MaterialEnumComboBox()
{
InitializeComponent();
}
}
Here is the converter for the MultiBinding.
public class InheritanceEnumValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.All(x => x.GetType().BaseType != typeof(Enum)))
throw new NotSupportedException();
else
{
Enum typedValue = values[0] as Enum;
Enum typedValue2 = values[1] as Enum;
string strAbbr = typedValue.Description(); // based on the Description attribute for the enum.
if (typedValue != null)
{
if (strAbbr == "Inherited")
strAbbr = typedValue2.ToString() + " " + "(" + "Inherited" + ")";
return strAbbr;
}
else
return string.Empty;
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
Type enumTargetType = targetTypes.First();
var enumValue = Enum.Parse(enumTargetType, value.ToString());
return new object[] { enumValue };
}
}
Here is the model. The ObservableObject is from Galasoft.MvvmLight.
public class MyModel: ObservableObject
{
private YesNoInherit _generateStatements;
private YesNoInherit _defaultGenerateStatements;
public YesNoInherit GenerateStatements
{
get { return _generateStatements; }
set
{
if (value != _generateStatements)
{
_generateStatements = value;
RaisePropertyChanged("GenerateStatements");
}
}
}
public YesNoInherit DefaultGenerateStatements
{
get { return _defaultGenerateStatements; }
set
{
if (value != _defaultGenerateStatements)
{
_defaultGenerateStatements = value;
RaisePropertyChanged("DefaultGenerateStatements");
}
}
}
}
Finally the enum.
public enum YesNoInherit
{
[Description("No")]
No = 0, ///<
[Description("Yes")]
Yes = 1, ///<
[Description("Inherited")]
Inherit = 2
}
The "DefaultGenerateStatements" property is always "Yes" for this example.
When the combo box first appears, the value is "Yes".
I change the value of the combo box in this order.
When I change from "Yes" to "No", the converter is not executed. I expect this.
When I change from "No" to "Yes", the converter is not executed. I expect this.
When I change from "Yes" to "Inherit", the converter executes, gets the value of DefaultGenerateStatements, and returns the text "Yes (Inherited)" to the combo box. I expect this.
When I change from "Inherit" to "Yes", the text "Yes" appears in the combo box as it should, but the converter is executed. I'm not sure if the converter should execute.
When I change from "Yes" to "No", the text "No" appears as it should, but the converter is executed. I don't believe the converter should execute.
After this, any change results in the converter being executed.
For steps 4 and 5, the DataTrigger fires when I don't think it should. Is there something wrong with my code?
I want to create a TextBox that can take measurement and convert it to different units if necessary (the end result being of type double). The conversion will be controlled by a value IsMetric. If IsMetric == true then "36.5 in" would turn into 927.1 (a double representing millimeters). Conversely, if IsMetric == false then "927.1 mm" would turn into 36.5.
I thought to use an IValueConverter on a regular TextBox, but the ConverterParameter is not a DependencyProperty and therefore I can't bind IsMetric to it.
I tried IMultiValueConverter but the ConvertBack function only receives the current value of the TextBox and not all the bound values. This means I don't know IsMetric when converting the user input.
Have I missed something with the ConvertBack function? If not, then do I need to create a class derived from TextBox?
You could use two converters one to convert from Metric and another to Metric:
public class ToMetricConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return "(metric) value";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class FromMetricConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return "(Inch) value";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And use a DataTrigger in the UI to select the appropriate converter based on that bool value:
<Window.Resources>
<wpfApplication13:ToMetricConverter x:Key="ToMetricConverter"/>
<wpfApplication13:FromMetricConverter x:Key="FromMetricConverter"/>
</Window.Resources>
<Grid>
<StackPanel>
<CheckBox IsChecked="{Binding IsMetric,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></CheckBox>
<TextBox >
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IsMetric,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Value="True">
<Setter Property="Text" Value="{Binding Val,Converter={StaticResource ToMetricConverter}}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding IsMetric,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Value="False">
<Setter Property="Text" Value="{Binding Val,Converter={StaticResource FromMetricConverter}}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</StackPanel>
</Grid>
If thats the only thing you want to do, try other way to use converter parameter.
But, and i would have choose this option - if your textbox has more logics in it, or tend to have more dependecie - Create custom control that inherits from textbox, and add your own dependecy properties. Then you can use your IsMetric and convert it as you want on propertychanged etc.
I ended up with something along these lines for now. Would still enjoy a solution that doesn't require a DataTrigger for every possible value.
It's a bit different than the answer posted by #SamTheDev but along the same lines.
xaml
<UserControl x:Class="MyNamespace.Controls.MeasurementTextBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:MyNamespace.Converters"
xmlns:b="clr-namespace:MyNamespace.Behaviors"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
x:Name="root">
<UserControl.Resources>
<c:MeasurementUnitConverter x:Key="muc"/>
<c:MeasurementConverter2 x:Key="mc"/>
<sys:Boolean x:Key="BooleanFalse">False</sys:Boolean>
<sys:Boolean x:Key="BooleanTrue">True</sys:Boolean>
</UserControl.Resources>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<TextBox Margin="0" VerticalContentAlignment="Center" HorizontalAlignment="Stretch" HorizontalContentAlignment="Right" VerticalAlignment="Stretch"
b:AutoSelectBehavior.AutoSelect="True">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding UseMetric, ElementName=root}" Value="True">
<Setter Property="Text" Value="{Binding Measurement, Mode=TwoWay, ElementName=root, Converter={StaticResource mc}, ConverterParameter={StaticResource BooleanTrue}}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding UseMetric, ElementName=root}" Value="False">
<Setter Property="Text" Value="{Binding Measurement, Mode=TwoWay, ElementName=root, Converter={StaticResource mc}, ConverterParameter={StaticResource BooleanFalse}}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<!-- in or mm label -->
<Label VerticalAlignment="Center" Padding="0" Margin="5" HorizontalAlignment="Left" Grid.Column="1"
Content="{Binding UseMetric, ElementName=root, Converter={StaticResource muc}}"/>
</Grid>
</UserControl>
xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;
namespace MyNamespace.Controls
{
/// <summary>
/// Interaction logic for MeasurementTextBox.xaml
/// </summary>
public partial class MeasurementTextBox : UserControl
{
public MeasurementTextBox()
{
// This call is required by the designer.
InitializeComponent();
}
public bool UseMetric {
get { return Convert.ToBoolean(GetValue(UseMetricProperty)); }
set { SetValue(UseMetricProperty, value); }
}
public static readonly DependencyProperty UseMetricProperty = DependencyProperty.Register("UseMetric", typeof(bool), typeof(MeasurementTextBox), new PropertyMetadata(MeasurementTextBox.UseMetricChanged));
private static void UseMetricChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public double Measurement {
get { return (double)GetValue(MeasurementProperty); }
set { SetValue(MeasurementProperty, value); }
}
public static readonly DependencyProperty MeasurementProperty = DependencyProperty.Register("Measurement", typeof(double), typeof(MeasurementTextBox), new PropertyMetadata(MeasurementTextBox.MeasurementPropertyChanged));
private static void MeasurementPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
}
}
Converter
using System;
using System.Windows;
using System.Windows.Data;
namespace MyNamespace.Converters
{
class MeasurementConverter : IValueConverter
{
const double MILLIMETERS_IN_ONE_INCH = 25.4;
const string INCHES_ABBREVIATION = "in";
const string MILLIMETERS_ABBREVIATION = "mm";
const double ONE_THIRTY_SECOND = 0.03125;
const double ONE_SIXTEENTH = 0.0625;
const double ONE_EIGHTH = 0.125;
const double ONE_FOURTH = 0.25;
const double ONE_HALF = 0.5;
const double ONE = 1;
public double RoundToNearest(double value, int unitPrecision)
{
double fraction = 0;
int reciprocal = 0;
switch (unitPrecision)
{
case 0:
fraction = ONE;
reciprocal = (int)ONE;
break;
case 1:
fraction = ONE;
reciprocal = (int)ONE;
break;
case 2:
fraction = ONE_HALF;
reciprocal = (int)(1 / ONE_HALF);
break;
case 3:
fraction = ONE_FOURTH;
reciprocal = (int)(1 / ONE_FOURTH);
break;
case 4:
fraction = ONE_EIGHTH;
reciprocal = (int)(1 / ONE_EIGHTH);
break;
case 5:
fraction = ONE_SIXTEENTH;
reciprocal = (int)(1 / ONE_SIXTEENTH);
break;
case 6:
fraction = ONE_THIRTY_SECOND;
reciprocal = (int)(1 / ONE_THIRTY_SECOND);
break;
}
return Math.Round(value * reciprocal, MidpointRounding.AwayFromZero) * fraction;
}
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string strValue = (string)value;
bool isMetric = (bool)parameter;
double enteredValue = 0;
bool enteredValueIsImperial = false;
if (strValue.EndsWith(INCHES_ABBREVIATION))
{
enteredValueIsImperial = true;
strValue = strValue.Substring(0, strValue.Length - INCHES_ABBREVIATION.Length);
}
else if (strValue.EndsWith(MILLIMETERS_ABBREVIATION))
{
enteredValueIsImperial = false;
strValue = strValue.Substring(0, strValue.Length - MILLIMETERS_ABBREVIATION.Length);
}
else if (isMetric)
{
enteredValueIsImperial = false;
}
else
{
enteredValueIsImperial = true;
}
try
{
enteredValue = double.Parse(strValue);
}
catch (FormatException)
{
return DependencyProperty.UnsetValue;
}
if (isMetric)
{
if (enteredValueIsImperial)
{
//inches to mm
return RoundToNearest(enteredValue * MILLIMETERS_IN_ONE_INCH, 0);
//0 is mm
}
else
{
//mm to mm
return RoundToNearest(enteredValue, 0);
//0 is mm
}
}
else
{
if (enteredValueIsImperial)
{
//inches to inches
return RoundToNearest(enteredValue, 5);
}
else
{
//mm to inches
return RoundToNearest(enteredValue / MILLIMETERS_IN_ONE_INCH, 5);
}
}
}
}
}
Usage:
<mynamespace:MeasurementTextBox Measurement="{Binding SomeLength, Mode=TwoWay}"
UseMetric="{Binding IsMetric}"/>
I would like to create WPF converter that converts double number to "+" or "-" String based on the number Sign(positive or negative)
but I can't handle the converted back method because I don't have the number anymore.
The "+" and "-" signs bounded to a combobox at the xaml side
any ideas???
public class AmountToDebitCreditConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ((value == null) || (System.Convert.ToDecimal(value) == 0))
return string.Empty;
return System.Convert.ToDecimal(value) > 0 ? "+" : "-";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
KeyValue kv = value as KeyValue;
if ((String)value == "+")
return 1;
else
return -1;
}
}
Here's my Xaml code
<igDP:UnboundField Name="ActualAdjustmentAmount" Label="PlusMinusKey" Converter={StaticResource signConverter} >
<igDP:Field.Settings>
<igDP:FieldSettings EditorType="{x:Type igEditors:XamComboEditor}" LabelWidth="40" CellWidth="40">
<igDP:FieldSettings.EditorStyle>
<Style TargetType="{x:Type igEditors:XamComboEditor}">
<Setter Property="ItemsSource" Value="{Binding Path=Flags, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" />
<Setter Property="FlowDirection" Value="LeftToRight"/>
<Setter Property="SelectedItem" Value="{Binding Path=ActualAdjustmentAmount }" />
</Style>
</igDP:FieldSettings.EditorStyle>
</igDP:FieldSettings>
</igDP:Field.Settings>
</igDP:UnboundField>
If the idea is not just to be able to use (and exploit) Converters, then I would rather suggest you to have a specific Sign property in your ViewModel and bind your view showing sign with that property.
It is probably best to do this sort of conversion in a view-model whenever possible.
Nonetheless, you've pinpointed the problem -- you no longer have the number after your conversion. The fact is that you don't need to return a string from your converter -- you can return any object that will return the desired string from its ToString() override, and that object can contain any other data and behaviour that you want.
Here is a converter that should accomplish what you're after, though I haven't actually tested this:
public class SignedDoubleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return new DisplaySignedDouble(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var d = value as DisplaySignedDouble;
return (d == null || !d.Value.HasValue)
? 0d
: d.Value.Value;
}
private class DisplaySignedDouble
{
public DisplaySignedDouble(object value)
{
Value = value is double ? (double) value : (double?) null;
}
public double? Value { get; private set; }
public override string ToString()
{
if (!Value.HasValue || Value.Value == 0d)
{
return string.Empty;
}
return Value.Value > 0 ? "+" : "-";
}
}
}
I have:
public class Person
{
String name { get; set; }
String address { get; set; }
bool isMarried { get; set; }
}
My datagrid gets populated with a list of persons.
I want to have a custom column where icon-1.jpg is displayed when isMarried is true and icon-2.jpg is displayed when isMarried is false.
How do I do this in WPF ? Any ideas ?
I know how to do a custom column but I do not know how to assoc the two states of isMarried with icon-1.jpg and icon-2.jpg.
You could do this with a DataTrigger in your custom column:
<DataGridTemplateColumn Header="Married">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image x:Name="IMG" Source="married_image" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=isMarried}" Value="False">
<Setter Property="Source" Value="not_married_image" TargetName="IMG"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
You can use an IValueConveter to convert from a Boolean value to an Uri (Uri is what you need for image source).
public class MarriedConverter : IValueConverter
{
public Object Convert(Object value, Type targetType, Object parameter, CultureInfo culture)
{
if ((value == null) || !(value is bool))
return null;
bool isMarried = (bool)value;
if (isMarried)
return new Uri(#1);
else
return new Uri(#2);
}
public Object ConvertBack(Object value, Type targetType, Object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}