The context is I have a Listbox that is outputting items with quite a lot of styling (more than i've put here)... I went to use a DataTemplateSelector to show either one image or another based on a condition but it was stupid to have to re-write the whole tempalte with just this one difference in it.
I have placed some pseudo code to demonstrate what i'm trying to achieve:
<ListBox Grid.Row="1"
ItemsSource="{Binding TestCases}"
BorderThickness="0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="10"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Padding="0,5,0,5">
<Run Text="{Binding Class}"></Run>
</TextBlock>
<TextBlock Grid.Column="1"
Padding="5">
<Run Text="{Binding Assertions}"></Run>
</TextBlock>
if {Binding Failures} > 0 {
<Image HorizontalAlignment="Center"
Width="10"
Height="10"
Grid.Column="2"
Source="/Content/Images/Cross.png">
</Image>
}
else
{
<Image HorizontalAlignment="Center"
Width="10"
Height="10"
Grid.Column="2"
Source="/Content/Images/Tick.png">
</Image>
}
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Any ideas on how i do it?
-------------Edit------------
So far i've added the namespace of my converter class to the XAML file:
xmlns:converters="clr-namespace:Blah.Blah.Converters"
Then added window resources:
<Window.Resources>
<converters:FailuresTickConverter x:Key="failuresTickConverter" />
<converters:FailuresCrossConverter x:Key="failuresCrossConverter" />
</Window.Resources>
Then i have the classes themselves:
namespace Blah.Blah.Converters
{
public class FailuresTickConverter : IValueConverter
{
public object Convert( object value, Type targetType,
object parameter, CultureInfo culture )
{
int failures = (int)value;
if( failures > 0 )
return Visibility.Hidden;
return Visibility.Visible;
}
public object ConvertBack( object value, Type targetType,
object parameter, CultureInfo culture )
{
throw new NotImplementedException();
}
}
public class FailuresCrossConverter : IValueConverter
{
public object Convert( object value, Type targetType,
object parameter, CultureInfo culture )
{
int failures = ( int )value;
if( failures > 0 )
return Visibility.Visible;
return Visibility.Hidden;
}
public object ConvertBack( object value, Type targetType,
object parameter, CultureInfo culture )
{
throw new NotImplementedException();
}
}
}
Then in my XAML on the images i've done this:
<Image Visibility="{Binding Failures, Converter=failuresTickConverter}"
HorizontalAlignment="Center"
Width="10"
Height="10"
Grid.Column="2"
Grid.Row="0"
Source="/Content/Images/Tick.png">
</Image>
<Image Visibility="{Binding Failures, Converter=failuresCrossConverter}"
HorizontalAlignment="Center"
Width="10"
Height="10"
Grid.Column="2"
Grid.Row="0"
Source="/Content/Images/Cross.png">
</Image>
I'm getting an error on the bindings:
IValueConverter does not support converting from string
Elaborating on my comment, here's a simple (not the only one, of course) way to do it:
Create a converter to convert number to visibility:
public class PositiveToVisibilityConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (int)value > 0 ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Add the namespace of the converter to your xaml, add the converter to resources (use your own namespace of course):
<Window ...
xmlns:converters="clr-namespace:WpfApplication1.Converters"
...>
<Window.Resources>
<converters:PositiveToVisibilityConverter x:Key="PositiveConverter"/>
</Window.Resources>
Then put both the images in, the "success" one first and bind the property using the converter to the "failure" one:
<Image HorizontalAlignment="Center"
Width="10"
Height="10"
Grid.Column="2"
Source="/Content/Images/Tick.png"
Visibility="{Binding Failures, Converter={StaticResource PositiveConverter}}">
</Image>
<Image HorizontalAlignment="Center"
Width="10"
Height="10"
Grid.Column="2"
Source="/Content/Images/Cross.png">
</Image>
Since these images are in a grid (I assume) and have the same position and size, they will overlap and normally the one that's defined last will be drawn last, so the first one will not be visible. That is, unless the binding makes the second image invisible.
Related
A CollectionView creates DateTime objects through a method. I would like the element with today's Datetime to have a different Grid background when opening the page.
<CollectionView
x:Name="ColCalendar">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid BackgroundColor="Gray" RowSpacing="0.1">
<Grid.RowDefinitions>
<RowDefinition Height="8"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Text="{Binding Giorno}" FontSize="8" TextColor="White" HorizontalTextAlignment="Center"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
The only method I know of to be able to change the background is the GestureRecognizer but it requires the user to press the button, instead I would like it to be automatic
use an IValueConverter
in your page (see docs for complete example)
<ContentPage.Resources>
<ResourceDictionary>
<local:DateColorConverter x:Key="DateColor" />
</ResourceDictionary>
</ContentPage.Resources>
...
<Grid BackgroundColor="{Binding DateField,Converter={StaticResource DateColor}}" RowSpacing="0.1">
then create a ValueConveter class
public class DateColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ( ((DateTime)value).Today == DateTime.Today) return Color.Blue;
return Color.Yellow;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
I'm using a ComboBox (WPF 4.0) to show user defined paragraph styles for an editor app. The ComboBox has two columns:
(1) Name of the paragraph style
(2) Text "abcABC123", should in some properties be formatted according to the paragraph style in the first column
(1) is working, (2) is not because _ResourceKey_background, _ResourceKey_foreground and _ResourceKey_fontFamily are no ResourceKeys
but variables containing ResourceKeys. How can I solve this?
_NameInternal, _NameUI, _ResourceKey_background, _ResourceKey_foreground and _ResourceKey_fontFamily are public properties
of the user defined paragraph style class.
<ComboBox Name="_cbStylesPara" SelectedValuePath="_NameInternal"
ItemsSource="{Binding Source={StaticResource _collectionViewSource_stylesPara}}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Text="{Binding _NameUI}" VerticalAlignment="Center" />
<TextBlock Grid.Column="1" Text="abcABC123" Margin="3,0,0,0" VerticalAlignment="Center"
Background="{DynamicResource _ResourceKey_background}"
Foreground="{DynamicResource _ResourceKey_foreground}"
FontFamily="{DynamicResource _ResourceKey_fontFamily}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
As like you said resources are declared under App resources, what you can do is create an IValueConverter and return the resource value from it's Convert method.
public class ResouceLookupConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return App.Current.TryFindResource(value);
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return Binding.DoNothing;
}
}
XAML:
<ComboBox>
<ComboBox.Resources>
<local:ResouceLookupConverter x:Key="ResouceLookupConverter"/>
</ComboBox.Resources>
......
<TextBlock Grid.Column="1" Text="abcABC123" Margin="3,0,0,0"
VerticalAlignment="Center"
Background="{Binding _ResourceKey_background,
Converter={StaticResource ResouceLookupConverter}}"
Foreground="{Binding _ResourceKey_foreground,
Converter={StaticResource ResouceLookupConverter}}"
FontFamily="{Binding _ResourceKey_fontFamily,
Converter={StaticResource ResouceLookupConverter}}" />
</ComboBox>
Note: Ofcourse you have to define local namespace in your XAML set to the namespace where your Converter is declared.
I have a Views/Doc.xaml with:
<navigation:Page ....
<data:DataGrid>
<data:DataGridTemplateColumn Header="Actions" HeaderStyle="{StaticResource TextHeaderStyle}" >
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid x:Name="gridDocumentColumns">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<HyperlinkButton x:Name="hlEmail" Grid.Column="1" Tag="{Binding Index}" Click="hlEmail_Click" >
<ToolTipService.ToolTip>
<ToolTip Tag="ToolTipEmail" Opened="toolTip_ActionOpened" />
</ToolTipService.ToolTip>
<Image Source="../images/close.png" Stretch="None" />
</HyperlinkButton>
</Grid>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
</data:DataGrid>
..............
I have a second class Views/Controls/ReadDocs.xaml (). If a certain condition in ReadDocs.xaml Code Behind is true i want to change the image source in Views/Doc.xaml to ../images/open.png
How can i achieve this?
You can define a converter and pass a flag value to it.
This converter will returns a specific path depending upon the value you have passed.
Kindly refer the below converter for reference...
public sealed class ImagetoPathConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null)
{
return value = "ms-appx:///Assets/Images/bk/1.png";
}
else if (value.ToString() == "1")
{
return value = "ms-appx:///Assets/Images/bk/2.png";
}
else if (value.ToString() == "2")
{
return value = "ms-appx:///Assets/Images/bk/3.png";
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Bind the converter in Source and pass your conditional value.
I have a data template with a TexBlock in XAML. This TexBlock shows a word in a word list. Every word I want to put the first letter capitalized, because all words are in lowercase.
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="AddrBookItemTemplate">
<StackPanel VerticalAlignment="Top">
<TextBlock Margin="5,0,0,0" FontSize="20" Text="{Binding name}" />
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
In c# implement the converter
namespace Converter.ViewModels
{
public class ToCapitalizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return char.ToUpper(value.ToString()[0]) + value.ToString().Substring(1);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (value as string).ToLower();
}
}
}
In App.xaml
...
xmlns:vm="clr-namespace:Converter.ViewModels"
<Application.Resources>
<vm:ToCapitalizeConverter x:Key="ToCapitalizeConverter"/>
</Application>
In MainPage.xaml
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="AddrBookItemTemplate">
<StackPanel VerticalAlignment="Top">
<TextBlock Margin="5,0,0,0" FontSize="20" Text="{Binding name, Converter={StaticResource ToCapitalizeConverter}}" />
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
You can use a converter as follows:
<TextBlock Margin="5,0,0,0" FontSize="20" Text="{Binding name, Converter ={StaticResource myConverter}}" />
Specific information on how to implement a converter can be found here. You can essentially perform any operation you like on the text. I actually like Humanizer to do these type of text conversions.
I'm trying to change an Image in a LongListSelector on basis of a boolean property of the DataContext of the LongListSelector. I'm using a ValueConverter in order to achieve this, and the code does reach the ValueConverter and returns a BitmapImage but this isn't visible on screen. Here's some of the relevant code:
XAML code (ItemTemplate and the ValueConverter declaration):
<local:BoolToImage x:Key="BoolImageConverter"/>
DataTemplate x:Key="itemTemplate">
<Grid Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Foreground="Black" Margin="0" FontFamily="Segoe WP Light" FontSize="29.333" VerticalAlignment="Center" Text="{Binding BeginTijdTimeOnly}" />
<TextBlock Grid.Column="1" TextWrapping="Wrap" Foreground="Black" Margin="0" FontFamily="/LimburgsLeed;component/Fonts/Fonts.zip#Champion" FontSize="48" VerticalAlignment="Center" Text="{Binding Artiest.Naam}" />
<Image x:Name="image" Grid.Column="2" Source="{Binding Path=isSaved, Converter={StaticResource BoolImageConverter}}" VerticalAlignment="Center" Margin="0, 0, -1, 0" MouseLeftButtonDown="fav_Click"/>
</Grid>
</DataTemplate>
As you can see the Image is bound to the ValueConverter and the isSaved property.
ValueConverter code:
public class BoolToImage : IValueConverter
{
public BitmapImage TrueImage = new BitmapImage();
public BitmapImage FalseImage = new BitmapImage();
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
TrueImage.UriSource = new Uri("/Images/ThumbSelected#2x.png", UriKind.RelativeOrAbsolute);
FalseImage.UriSource = new Uri("/Images/thumb.png", UriKind.RelativeOrAbsolute);
if (!(value is bool))
{
return this.FalseImage;
}
bool b = (bool)value;
if (b)
{
return this.TrueImage;
}
else
{
return this.FalseImage;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I don't have a clue why the image isn't shown.. The ValueConverter CAN'T return null.
My god, I sure feel stupid now. This all works fine, but I set the Image files their Build Action to Embedded Resource. Changing it to content resolved the problem.