Binding to a Rectangle within a ListBox ItemTemplate? - c#

I have a ListBox, which uses data binding for content (bound to an ObservableCollection), and an ItemTemplate for layout. Within the ItemTemplate, there is a TextBlock displaying a date (from the ObservableCollection), and a colored Rectangle.
I want the rectangle's fill color to change based on the date (to indicate age). However, since the Rectangle itself isn't bound to the date (and I don't see how it could be), I haven't been able to get a DataTrigger to work to alter the fill color.
Is there another way to get the Rectangle color to be controlled by the data binding?
Edit:
Here is a (simplified) copy of my ListBox ItemTemplate, as requested. Right now, the Rectangle's fill is a set color, but I want to change it to vary based on the targetstartdate field.
<ListBox Name="listBox1" ItemsSource="{Binding Path=testList}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Rectangle Fill="#FF009A00" Width="5" StrokeThickness="1" Margin="0,1,4,1"/>
<TextBlock Text="{Binding targetstartdate}" Margin="0,0,0,4" Foreground="#FF009A00" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

You can bind the rectangle's Fill or Stroke property to the Date. Then, use an IValueConverter to convert the date to the appropriate color.
<Window.Resources>
<local:DateToBrushConverter x:Key="DateToBrushConverter" />
</Window.Resources>
<Rectangle Fill="{Binding targetstartdate,Converter={StaticResource DateToBrushConverter}}"
... />
The Convert method should return a Brush object, which matches the Rectangle.Fill property.
public class DateToBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var date = value as DateTime?;
if (!date.HasValue)
return new SolidColorBrush(Colors.Transparent);
else if (!date.Value > DateTime.Today.AddDays(-1))
return new SolidColorBrush(Colors.Blue);
// etc
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Bind rectangle's color to an IValueConverter, use the date as binding and determine the color based on the date inside the IValueConverter class.

Related

Image not showing after collapsed

I am running into a strange situation where the image won't show up if its visibility is first set to collapsed and latter set to visible through binding.
<ListView Grid.Row="0" ItemsSource="{Binding SystemCheckEntries}">
<GridViewColumn DisplayMemberBinding="{Binding State}" />
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="info.png"
Height="14"
ToolTip="{Binding Message}"
Visibility="{Binding Message, Converter={StaticResource StringNullOrEmptyToVisibilityConverter}}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Converter:
public class StringNullOrEmptyToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return string.IsNullOrEmpty((string) value) ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
if I use Visibility.Collapsed in converter then the result looks like
and if I open up visual tree to check the property of the image
which says its suppose to be "Visible" (but apparently not)
If I use Visibility.Hidden in converter then the result looks like
Which is exactly what I wanted. But then I don't want the icon to take up extra space when its not showing.
So .. why is this happening?
Some conjecture: The first items have no width (because they are collapsed), the ListView sets the column width to 0. New items are added that have an image but it's not shown because the column has no width.
Edit: Just confirmed this behaviour.

Assign an Image for each Pivot Item Header

I am trying to assign an image for each of my pivot items's header instead of a Text .
I tried several methods (one was given by this post http://social.msdn.microsoft.com/Forums/wpapps/en-US/e7b5fd17-3465-4a94-81af-5c056c992c11/add-image-to-pivot-title?forum=wpdevelop )
I managed to assign the same image for my pivot but not one image for each header.
This is what I tried :
<phone:Pivot.HeaderTemplate >
<DataTemplate>
<Image Source="21.jpg" Height="55" Width="55"/>
</DataTemplate>
</phone:Pivot.HeaderTemplate>
This obviously gave me the same image for each headers ,
So i wanted to try something like this :
<phone:Pivot.HeaderTemplate >
<DataTemplate>
<Image Source="{Binding}" Height="55" Width="55"/>
</DataTemplate>
</phone:Pivot.HeaderTemplate>
[...]
<phone:PivotItem ??? >
<// phone:PivotItem >
But then i don't know what to add my image path.
i used this method when i wanted to assign a text as a header and it worked :
<phone:Pivot.HeaderTemplate >
<DataTemplate>
<TextBlock Text="{Binding }" FontSize="88" />
</DataTemplate>
</phone:Pivot.HeaderTemplate>
<phone:PivotItem Header = "Title1" />
How can i assign an image for each of my Header ?
You should be able to simply provide the image source in the Header:
<phone:PivotItem Header = "21.jpg" />
This sets the data context to use for the HeaderTemplate for that particular item.
You need to use a Converter Class to solve this issue.
namespace MyImageConvertor
{
public class MyValueConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
var uri = new Uri((string)(value), UriKind.RelativeOrAbsolute);
var img = new BitmapImage(uri);
return img;
}
catch
{
return new BitmapImage();
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var img = value as BitmapImage;
return img.UriSource.AbsoluteUri;
}
#endregion
}
}
Then use the this convertor in your xaml.
<UserControl x:Class="ValueConverter.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:this="clr-namespace:MyImageConvertor">
<UserControl.Resources>
<this:MyValueConverter x:Key="ImageConverter"/>
</UserControl.Resources>
<phone:Pivot>
<phone:Pivot.HeaderTemplate>
<DataTemplate>
<Image Source="{Binding ImageUrlProperty, Converter={StaticResource ImageConverter},Mode=TwoWay}"></Image>
</DataTemplate>
</phone:Pivot.HeaderTemplate>
</phone:Pivot>
Make sure you have the full image path in the ImageUrlProperty value like ..\Images\logo.png.

wpf listview adding images into a listviewitem at runtime

Hi guys I am working on a project in C# WPF where I need to display a client's status in a listview
So I have the following enum that defines a Client Status
//Values used here for Bitwise Operations
public enum ClientStatus
{
NONE = 0,
NEWCLIENT = 1,
MONITORED = 2,
IMPORTAND = 4,
DISATISFIED = 8,
DETERIORATING = 16,
SATISFIED = 32
};
To Convert Each to a specific Brush I have the following code, Tested and it works
[ValueConversion(typeof(Enums.ClientStatus), typeof(Brush))]
public class StateValueColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Brush Brush = Brushes.Red;
if (value is Enums.ClientStatus)
{
Enums.ClientStatus sv = (Enums.ClientStatus)value;
switch (sv)
{
case Enums.ClientStatus.IMPORTAND:
Brush = Brushes.Blue;
break;
case Enums.ClientStatus.MONITORED:
Brush = Brushes.Purple;
break;
case Enums.ClientStatus.NEWCLIENT:
Brush = Brushes.Orange;
break;
case Enums.ClientStatus.SATISFIED:
Brush = Brushes.Green;
break;
case Enums.ClientStatus.DETERIORATING:
Brush = Brushes.Yellow;
break;
case Enums.ClientStatus.DISATISFIED:
Brush = Brushes.Red;
break;
}
}
return Brush;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
to do the Binding I did the following, which is not what our lecturer exactly wanted
<GridViewColumn Header="Status" Width="110">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Width="50" Background="{Binding Path=Status, Converter={StaticResource ColorConverter}}"></TextBox>
<TextBox Width="50" Background="{Binding Path=SatisFactory, Converter={StaticResource ColorConverter}}"></TextBox>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
We need to display each of the enums as a different color however a client can have multiple statuses i.e
var status = ClientStatus.NEWCLIENT | ClientStatus.SATISFIED;
This will now return a int value of 33
My Problem now is I used two properties in my Client to show seperate statuses which is incorrect we need to use Bitwise Operations ie.
if ((status & ClientStatus.NEWCLIENT) == ClientStatus.NEWCLIENT)
{
//do whatever
}
so I can do the above code but how would I do the binding on one property to show multiple color's in the one gridviewcollumn, I search the forum but I missed it if this question or something similar was there
I am not really sure how to state the question so I will try it in other words
I want to display all selected enums in the column.
Thanks for any help or suggestions
Hope I made sence
If I understand your question correctly, you'd like to display an icon, image, or UI element for each value in the enumeration and have them be visible if the object's status matches that value.
I think I would create a simple StackPanel containing all the UI elements likes so:
<StackPanel Orientation="Horizontal">
<Rectangle Fill="Blue"
Visibility="{Binding Status,
Converter={StaticResource StatusToVisibilityConverter},
ConverterParameter=NEWCLIENT}" />
<Rectangle Fill="Green"
Visibility="{Binding Status,
Converter={StaticResource StatusToVisibilityConverter},
ConverterParameter=SATISFIED}" />
...
</StackPanel>
Then in your StatusToVisibilityConverter compare the value of Status with the value in ConverterParameter (you can convert that to you enumeration's value with TryParse static method.
Hope that helps.
Define DataTemplate name StatusDataTemplate, or a default DataTemplate for Enums.ClientStatus as TargetType.
In this template, define a 3 columns X 2 rows Grid.
In each grid cell, define a Border, having as background the binding using one of the 6 enum as ConverterParameter, with a converter that returns the 'right' color if value AND parameter = parameter, transparent otherwise.
Then you can use :
<ContentPresenter Content="{Binding Status}" />
... if you used a default DTpl
Or :
<ContentPresenter Content="{Binding Status}" ContentTemplate="{StaticResource StatusTemplate}"/>

Unable to apply string formatting in Silverlight DataGrid column

I have a Data Grid. Its Item source is set to a List. My problem is that Iam unable to apply string formatting . This is formats Ive tried . Am I missing some thing ?
StringFormat='MM/dd/yyyy'
StringFormat={0:dd-MMM-yyyy}
Attached the resultant grid
<sdk:DataGridTemplateColumn Header="Recieved Date" Width="Auto" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=RecievedDate, StringFormat=\{0:dd-MMM-yyyy\} }" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<sdk:DatePicker Name="dtpFinancialAndComplianceLog" Text="{Binding Path=RecievedDate,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
If I understand what you're trying to do correctly, you have a DataGrid column which you want to display a DateTime object in a certain format. Ordinarily a DateTime object will sort out its own formatting depending on the System.Threading.Thread.CurrentUICulture.
Easiest way I know of to force any object into a certain format is to use a custom IValueConverter:
namespace MyProject.Converters
{
public class FormatConverter : IValueConverter
{//Suitable only for read-only data
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return string.Empty;
if(string.IsNullOrEmpty(parameter.ToString()))
return value.ToString();
return string.Format(culture, parameter.ToString(), value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}
After adding a namespace to your xaml: xmlns:conv="clr-namespace:MyProject.Converters" and declaring your converter in the control's resources <conv:FormatConverter x:Key="Formatter" />, you will need to bind your column's data using your new converter:
<TextBlock Text="{Binding Path=RecievedDate, Converter={StaticResource Formatter}, ConverterParameter=\{0:dd-MMM-yyy\} }" />

TextBlock as big as a capital letter (ignoring font ascender/descender)

I am looking to get a specific behavior on TextBlock so that its height only includes the height of the capital letters (from baseline to top minus "ascender height"). Please see the image Sphinx from Wikipedia to see what I mean. Also the image below may indicate better what I am after.
I am not specifically looking for a pure XAML solution (probably impossible) so a C# code behind (a converter) is also fine.
This is the XAML used in XamlPad to produce the left A in the image above.
<TextBlock Text="A" Background="Aquamarine" FontSize="120" HorizontalAlignment="Center" VerticalAlignment="Center" />
u can try to use attribute LineStackingStrategy="BlockLineHeight" and a Converter on the LineHeight attributes and a converter on the Height of TextBlock.
This a sample code of converters
// Height Converter
public class FontSizeToHeightConverter : IValueConverter
{
public static double COEFF = 0.715;
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (double)value * COEFF;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
// LineHeightConverter
public class FontSizeToLineHeightConverter : IValueConverter
{
public static double COEFF = 0.875;
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return double.Parse(value.ToString()) * COEFF;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
The Coefficient used on converters depends on Used Family Fonts (Baseline and LineSpacing):
<TextBlock Text="ABC" Background="Aqua" LineStackingStrategy="BlockLineHeight"
FontSize="{Binding ElementName=textBox1, Path=Text}"
FontFamily="{Binding ElementName=listFonts, Path=SelectedItem}"
Height="{Binding RelativeSource={RelativeSource Self}, Path=FontSize, Mode=OneWay, Converter={StaticResource FontSizeToHeightConverter1}}"
LineHeight="{Binding RelativeSource={RelativeSource Self}, Path=FontSize, Converter={StaticResource FontSizeToLineHeightConverter}}"/>
The best solution is to find how to calculate the Coeff based on parameters Baseline and LineSpacing of the FontFamily.
In this sample (Segeo UI) the Coeff of Height = 0.715 and LineHeight = 0,875 * FontSize.
Updated:
If I understand right, there's a few tricks I know for this,
You can Scale it with RenderTransform which is usually the most efficient way;
<TextBlock Text="Blah">
<TextBlock.RenderTransform>
<CompositeTransform ScaleY="3"/>
</TextBlock.RenderTransform>
</TextBlock>
Or you can embed the TextBlock in a Viewbox to "zoom" the text to fit the bounds of its container if for example you set hard height values on grid rows like;
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="120"/>
<RowDefinition Height="120"/>
</Grid.RowDefinitions>
<Viewbox VerticalAlignment="Stretch" Height="Auto">
<!-- The textblock and its contents are
stretched to fill its parent -->
<TextBlock Text="Sphinx" />
</Viewbox>
<Viewbox Grid.Row="2" VerticalAlignment="Stretch" Height="Auto">
<!-- The textblock and its contents are
stretched to fill its parent -->
<TextBlock Text="Sphinx2" />
</Viewbox>
or you can bind the FontSize to a Container element like;
<Grid x:Name="MyText" Height="120">
<TextBlock FontSize="{Binding ElementName=MyText, Path=Height}" Text="Sphinx" />
</Grid>
They might present the effect you're after?

Categories