IValueConverter in ResourceDictionary - c#

I'm trying to use a Converter inside a ResourceDictionary. That's the code I have:
<Window x:Class="Metro.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cnv="clr-namespace:Metro.converters">
<Window.Resources>
<cnv:DarkenColorConverter x:Key="Darken" />
<Color x:Key="Red">#FF0000</Color>
<SolidColorBrush Color="{StaticResource Red}"
x:Key="Accent" />
<SolidColorBrush Color="{Binding Source={StaticResource Red}, Converter={StaticResource ResourceKey=Darken}}"
x:Key="DarkAccent" />
</Window.Resources>
<StackPanel>
<Grid Background="{StaticResource Accent}">
<TextBlock>grid 1</TextBlock>
</Grid>
<Grid Background="{StaticResource DarkAccent}">
<TextBlock>grid 2</TextBlock>
</Grid>
</StackPanel>
</Window>
Here's the converter:
public class DarkenColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Brushes.Blue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Brushes.Gray;
}
}
But somehow it's not working. As soon as I use the converter inside the Grid directly, everything works fine:
<Grid Background="{Binding Source={StaticResource Red}, Converter={StaticResource ResourceKey=Darken}}">
<TextBlock>grid 2</TextBlock>
</Grid>
What`s wrong with the first xaml sample?

In the first conversion you are converting a Color, the one in the Grid is converting a SolidColorBrush.
You will have to modify your converter to accept Color also.
public class DarkenColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double percentage = 0.8;
if (parameter != null)
{
double.TryParse(parameter.ToString(), out percentage);
}
if (value is SolidColorBrush)
{
Color color = (value as SolidColorBrush).Color;
return new SolidColorBrush(Color.FromRgb((byte)(color.R * percentage), (byte)(color.G * percentage), (byte)(color.B * percentage)));
}
else if (value is Color)
{
Color color = (Color)value;
return Color.FromRgb((byte)(color.R * percentage), (byte)(color.G * percentage), (byte)(color.B * percentage));
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}

The problem was the wrong converter return type.
Working converter:
public class DarkenColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Colors.Blue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Colors.Gray;
}
}

Related

IntToVisibilityConverter In WPF

I have a StackPanel and Border and what I need to achieve is whenever the Children.Count property of the panel is 0 the Border become visible. I tried to many times but don't know what's wrong with my code!?
public class IntToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value is int integer && integer == 0) ? Visibility.Visible : Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
Xaml
<local:IntToVisibilityConverter x:Key="IntConverter"/>
<Border Visibility="{Binding ElementName=MainPagesStackPanel, Path=Children.Count, Converter={StaticResource IntConverter}}"/>

Trying to create an IsFirstItem and IsLastItem IValueConverter for object collection bindings

The end goal to be able to set a specific ItemContainerStyle on the first and last element in my list box;
The converters thus far are:
public class IsFirstItemConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool result = false;
result = ((IList<object>)parameter).First() == value;
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class IsLastItemConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool result = false;
result = ((IList<object>)parameter).Last() == value;
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
And implementation:
<DataTrigger Value="True" Binding="{Binding Converter={StaticResource IsFirstItemConverter},ConverterParameter=Items, ElementName=SubItems}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="First"/>
<ContentPresenter/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
And the error is:
InvalidCastException: Unable to cast object of type 'System.String' to
type 'System.Collections.Generic.IList`1[System.Object]'.
Im sure I screwed up in multiple spots, just not experienced enough with XAML and bindings to narrow down where.
The following adapted from the questions comments work perfectly:
public class IsLastItemConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DependencyObject item = (DependencyObject)value;
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);
return ic.ItemContainerGenerator.IndexFromContainer(item) == ic.Items.Count - 1;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class IsFirstItemConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DependencyObject item = (DependencyObject)value;
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);
return ic.ItemContainerGenerator.IndexFromContainer(item) == 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class IsOnlyItemConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DependencyObject item = (DependencyObject)value;
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);
return (ic.ItemContainerGenerator.IndexFromContainer(item) == 0 && ic.ItemContainerGenerator.Items.Count == 1);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Implementation:
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource IsLastItemConverter}}" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="└"/>
<ContentPresenter/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
The magic seems to be that ItemsControlFromItemContainer makes it so I do not have to pass both the item and its collection instance to the converter but just the item and the converter can infer the parent collection.

set cursor to hand on empty image-control

I have the following xaml:
<Border x:Name="brdImg3" BorderThickness="2" BorderBrush="Black" Margin="10,5,5,5" Cursor="Hand">
<Image x:Name="image3" Stretch="Fill" Cursor="Hand"/>
</Border>
The problem is, that the Hand-Cursor is only shown when the Source of Image is not null. When the Source is null, the Hand-Cursor is only shown when the Mouse is over the border. I need showing the Hand-Cursor when the Mouse is in the Border. How can I do this?
Use Converter in Cursor, check sources is null or empty. Logic is writen
Cursor={Binding Source,Converter={StaticResources CursorConverter}
public class CursorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!string.IsNullorEmpty(value.Tostring()))
{
return Cursor.Hand;
}
else
{
return Cursor.Arrow;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

Binding to Canvas.TopProperty with adding some value

I have this code:
<Rectangle x:Name="cage" Height="247" Canvas.Left="278" Canvas.Top="220" Width="450">
<Rectangle.Fill>
<ImageBrush Stretch="None" ImageSource="resources/cage.gif"/>
</Rectangle.Fill>
</Rectangle>
and
<Label x:Name="to1" Content="1" Canvas.Left="550" Canvas.Top="{Binding Source=cage, Path=Canvas.Top, Mode=OneWay}" BorderBrush="#FF272727" BorderThickness="1" Height="38" Width="38" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontSize="20" PreviewMouseDown="to1_PreviewMouseDown"/>
Binding is working, but I want to maintain locations of this element relative to each other. Another words, if i shift the cage, topProperty of label became "shifting value + 285". How to do this?
Consider using a converter for this purpose as bit suggested.
A simple example should look like this:
XAML
<UserControl.Resources>
<converterNamespace:LabelOffsetConverter x:Key="labelOffsetConverter"/>
</UserControl.Resources>
<Label x:Name="to1" Content="1" Canvas.Left="550"
Canvas.Top="{Binding Source=cage, Path=Canvas.Top, Mode=OneWay,
Converter={StaticResource labelOffsetConverter}"
BorderBrush="#FF272727"
BorderThickness="1"
Height="38" Width="38"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
FontSize="20" PreviewMouseDown="to1_PreviewMouseDown"/>
Converter Code
public class LabelOffsetConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is double))
return DependencyProperty.UnsetValue;
double doubleValue = (double)value;
return doubleValue + 285;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// No need to implement, since the binding is in one way mode.
throw new NotImplementedException();
}
}
Solved by this way:
C#
public class Label1offset : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is double))
return DependencyProperty.UnsetValue;
double doubleValue = (double)value;
return doubleValue + 65.0;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// No need to implement, since the binding is in one way mode.
throw new NotImplementedException();
}
}
Binding binding1 = new Binding();
binding1.Converter = new Label1offset();
binding1.Source = cage;
binding1.Path = new PropertyPath(Canvas.TopProperty);
binding1.Mode = BindingMode.OneWay;
to1.SetBinding(Canvas.TopProperty, binding1);

Unknown attribute Foreground on element TextBlock WP 7

Unknown attribute Foreground on
element TextBlock
I have this error, when I'm trying to
change the Foreground color depending
on "Read_State"
public class ReadConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool ReadState =(bool)parameter;
if (ReadState == false)
return new SolidColorBrush(Colors.Black);// new SolidColorBrush((Color)Application.Current.Resources["PhoneAccentColor"]);
else
return new SolidColorBrush(Colors.Black);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
In Xaml
<TextBlock Foreground="{Binding Converter={StaticResource ReadConverter},ConverterParameter={Binding Read_State}}" Text="{Binding Path=TexT}" Style="{StaticResource PhoneTextNormalStyle}" TextWrapping="Wrap"/>
The error may just be a bit misleading. You can't use Binding on the ConverterParameter.
You are miss using the converter, you don't need the ConverterParameter at all. Your converter code ought to look like this:-
public class ReadConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool ReadState =(bool)value;
if (ReadState == false)
return new SolidColorBrush(Colors.Black);// new SolidColorBrush((Color)Application.Current.Resources["PhoneAccentColor"]);
else
return new SolidColorBrush(Colors.Black);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
and your Xaml:-
<TextBlock Foreground="{Binding Read_State, Converter={StaticResource ReadConverter}}" Text="{Binding Path=TexT}" Style="{StaticResource PhoneTextNormalStyle}" TextWrapping="Wrap"/>
You might also want to have a read of this blog for future use.

Categories

Resources