WPF DataGrid icon and boolean value - wpf

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();
}
}

Related

Binding property to visibility of other element

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);
}
}

ComboBox DataTemplate in WPF datagrid with binding not initialized

I have a binding list of Models and a DataGrid. Value can be of couple of data types (bool, double).
public class Model
{
public object Value { get; set; }
}
public void Initialize()
{
var models = new BindingList<Model>();
models.Add(new Model(){ Value = "hello"});
models.Add(new Model(){Value=true});
signals.ItemsSource = models;
}
I want to display the data in the data grid and I want to use textbox for numbers, but combo(true/false) for boolean values.So I implemented bool2string converter and DataTemplateSelector. In my example I have one text column and one template column displaying the same data. When I start the application the combo values are not initialized (nothing is selected). Once I start playing with values, everything works,the values are properly synchronized (if I change value in one column, it will propagate to the other column). Do you have any idea, what mistake I'm doing?
public class BoolToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((bool)value == true) ? "true" : "false";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var comboValue = (value as ComboBoxItem).Content.ToString();
return (String.Compare(comboValue, "true", StringComparison.InvariantCultureIgnoreCase) == 0);
}
}
public class DynamicDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var element = container as FrameworkElement;
var signal = item as Model;
if (element != null && signal != null)
{
if (signal.Value is bool)
return element.FindResource("BoolTemplate") as DataTemplate;
else
return element.FindResource("TextTemplate") as DataTemplate;
}
return null;
}
}
My xaml looks like following:
<Window.Resources>
<comboQuestion:DynamicDataTemplateSelector x:Key="DataTemplateSelector"/>
<comboQuestion:BoolToStringConverter x:Key="BoolToStringConverter"/>
</Window.Resources>
<Grid>
<DataGrid Grid.Row="1" Name="signals" AutoGenerateColumns="False" ItemsSource="{Binding}" >
<DataGrid.Resources>
<DataTemplate x:Key="BoolTemplate">
<ComboBox SelectedItem="{Binding Value, Converter={StaticResource BoolToStringConverter}, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ComboBoxItem>true</ComboBoxItem>
<ComboBoxItem>false</ComboBoxItem>
</ComboBox>
</DataTemplate>
<DataTemplate x:Key="TextTemplate">
<TextBox Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="TextValue" Binding="{Binding Value}"/>
<DataGridTemplateColumn Header="DynamicValue" CellTemplateSelector="{StaticResource DataTemplateSelector}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
EDIT:
I tried to change the SelectedItem to SelectedValue and I also tried to change the Convert part of the converter to:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var cbi = new ComboBoxItem();
cbi.Content = ((bool)value == true) ? "true" : "false";
return cbi;
}
however, the behavior remains the same.
You can convert a boolean to an index number using the following converter:
public class BooleanToIndexConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((bool)value == true) ? 0 : 1;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((int)value == 0) ? true : false;
}
}
Then bind to SelectedIndex on the ComboBox:
SelectedIndex="{Binding Value, Converter={StaticResource BooleanToIndexConverter}}

Changing element height depending on a selection of combobox

I have a combobox for selecting media types. I would like mediaelement's height to change when .vmw, .mpeg or .avi files are selected. How can I achieve this with MVVM approach?
Thanks in advance
You could bind the Width and Height of the MediaElement directly to its Source property with an appropriate converter, which selects the proper size depending on the media type:
<MediaElement
Width="{Binding Path=Source, RelativeSource={RelativeSource Self}, Converter={StaticResource MediaElementSizeConverter}, ConverterParameter=Width}"
Height="{Binding Path=Source, RelativeSource={RelativeSource Self}, Converter={StaticResource MediaElementSizeConverter}, ConverterParameter=Height}"/>
The converter:
public class MediaElementSizeConverter : IValueConverter
{
private const double defaultWidth = 320d;
private const double defaultHeight = 240d;
private const double wmvWidth = 640d;
private const double wmvHeight = 480d;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Uri source = value as Uri;
if (source != null)
{
if (source.AbsolutePath.EndsWith(".wmv"))
{
return (parameter as string) == "Width" ? wmvWidth : wmvHeight;
}
// more media types ...
}
return (parameter as string) == "Width" ? defaultWidth : defaultHeight;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
One solution would be to bind the ComboBox to a list of self created MediaTypeDefinition classes.
public class MediaTypeDefinition
{
public string Name { get; set; }
public int Height { get; set; }
}
You can then bind the SelectedItem to the height of the media element.
<ComboBox x:Name="mediaTypeList" ItemsSource="{Binding Definitions}" SelectedValuePath="Name" />
<MediaElement Height="{Binding SelectedItem.Height, Elementname=mediaTypeList}" />

Convert and Convertback between double and "+" & " -" String

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 ? "+" : "-";
}
}
}

Silverlight 4: how to switch control visibility

I am using MVVM in my Silverlight app. When control visibility is need to be managed by data, I am connecting its 'Visibility' property to object's corresponding property:
XAML:
<TextBlock Text="Price" Visibility="{Binding PriceVisibility, Mode=OneWay}"/>
<TextBox Text="{Binding TicketPrice, Mode=TwoWay}" Visibility="{Binding PriceVisibility, Mode=OneWay}"/>
CodeBehind (C#):
public string PriceVisibility { get { return PriceVisible ? "Visible" : "Collapsed"; } }
But from my perspective, returning string representation of the Visibility property is not a best approach.
Could you please advise if there are any better way?
Thanks!
I just used Reflector to inspect the type converters in the PresentationFramework.dll
There is already an implementation that can convert between boolean and visibility. You should be able to make use of this in your silverlight application.
public sealed class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool flag = false;
if (value is bool)
{
flag = (bool) value;
}
else if (value is bool?)
{
bool? nullable = (bool?) value;
flag = nullable.HasValue ? nullable.Value : false;
}
return (flag ? Visibility.Visible : Visibility.Collapsed);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((value is Visibility) && (((Visibility) value) == Visibility.Visible));
}
}
I've faced the problem of binding a Boolean value to the visibility property, so I've implemented my own Boolean to Visibility Converter, I'm using it with most of my applications.
Add the Following Class to your application:
public class BoolVisibilityConverter : IValueConverter{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture){
bool isVisible = (bool)value;
return isVisible ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){
System.Windows.Visibility currVisibility = (System.Windows.Visibility)value;
return (currVisibility == System.Windows.Visibility.Visible);
}
}
Now To Use it you'll need to add it as a resource in your XAML Code.
<UserControl.Resources>
<Helpers:BoolVisibilityConverter x:Key="boolVisibilityConverter" />
</UserControl.Resources>
In your example use the following:
<TextBlock Text="Price" Visibility="{Binding PriceVisibility, Mode=OneWay, Converter={StaticResource boolVisibilityConverter}}"/>
<TextBox Text="{Binding TicketPrice, Mode=TwoWay}" Visibility="{Binding PriceVisibility, Mode=OneWay, Converter={StaticResource boolVisibilityConverter}}"/>

Resources