How to implement a Converter - wpf

I have a list of objects that I'm binding to the screen. One of the properties is isPurchased. It is a Boolean type.
I don't have a lot of experience with converters so I'm finding this a little difficult. I have 2 questions.
The 1st question is regarding syntax. I copied this example from here.
public class purchasedConverter : IValueConverter
{
public object Convert(inAppPurchases value, Type targetType, object parameter, string language)
{
return;
}
}
If the isPurchased == true then I'd like to set the background color to my stackpanel to a different color.
I changed object value to inAppPurchases value on the Convert method. However, no matter what I tried I could not get a reference to a Background.
I think I want to return Background="somecolor"
My 2nd question (assuming I can do the 1st part), is I'm using StandardStyles.xaml which comes with the Microsoft WinRT projects So my converter would exist there.
<StackPanel Grid.Column="1" VerticalAlignment="Top"
Background="CornflowerBlue" Orientation="Vertical" Height="130"
Margin="0,0,5,0"/>
However, like I said I've tried this before but I wasn't able to figure out how to add the convert to my .xaml file. Where would I reference the converter? Is it on the StandardStyls.xaml or the main .xaml that I'm viewing?
Any help is appreciated.

Background property of StackPanel is type of Brush (Panel.Background msdn) , so we can return object of type SolidColorBrush from Convert method.
Your converter should look like this:
class PurchasedConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// isPurchased is bool so we can cast it to bool
if ((bool)value == true)
return new SolidColorBrush(Colors.Red);
else
return new SolidColorBrush(Colors.Orange);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Next you must create instance of this converter in XAML:
<Window.Resources>
<con:PurchasedConverter x:Key="pCon" />
</Window.Resources>
And now you can use this converter to binding Background property in StackPanel:
<StackPanel VerticalAlignment="Top" Orientation="Vertical" Height="130"
Background="{Binding isPurchased, Converter={StaticResource pCon}}"
Margin="0,0,5,0" >
</StackPanel>

Related

WPF; Convert simple string into my TextBlock Text failed and due to Cannot find resource named

So i have this TextBlock:
<TextBlock
Name="tbVersion"
Text="{Binding Converter={StaticResource TextConverter}}"/>
Converter:
public class TextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return "bla bla";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
And i got this error when try to run my application:
{"Cannot find resource named 'TextConverter'. Resource names are case
sensitive."}
Although there is no compiler errors at all and i declare this:
<Window.Resources>
<Convertors:TextConverter x:Key="TextConverter"/>
</Window.Resources>
Ok so i try to take another Converter that works from another TextBlobk and still got this error that cannot find resource although this exist (and works as i mentioned...) so maybe because my TextBlobk is inside DataTemplate :
<Controls:MetroWindow.TitleTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock
Name="tbVersion"
Text="{Binding Converter={StaticResource TextConverter}}"/>
</StackPanel>
</DataTemplate>
</Controls:MetroWindow.TitleTemplate>
As you can see from the image, i used exactly your code, and is working just fine.
So you may have added the converter to Window.Resources but you are using it in a different ResourceDictionary?
If you want to make them globally usable you should add them to the App.xaml, or programmatically to the Application.Current.ResourceDictionary
EDIT:
Try adding the converter to the DataTemplate.Resources

Convert Enum to string inside TextBlock text

I have simple Enum:
public enum StatusMessage
{
Cancel,
Done,
[Description("In process...")]
InProcess,
[Description("We have delay...")]
Delay,
Waiting
}
And GridViewColumn:
My property:
StatusMessage StatusMsg;
XAML:
<GridViewColumn Width="180" Header="Status" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding StatusMsg}" Foreground="{Binding StatusMsg,Converter={my:StatusMessageToColorConverter}}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
And i have this EnumToStringConverter:
public class EnumToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string EnumString;
try
{
EnumString = Enum.GetName((value.GetType()), value);
return EnumString;
}
catch
{
return string.Empty;
}
}
// No need to implement converting back on a one-way binding
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Now i want to use this Convertor inside my TextBlock :
<TextBlock Text="{Binding StatusMsg, Converter={my:EnumToStringConverter}}" Foreground="{Binding StatusMsg,Converter={my:StatusMessageToColorConverter}}" />
So the problem is that i have this error:
'my:EnumToStringConverter' is used like a markup extension but does
not derive from MarkupExtension.
What is this MarkupExtension ?
You need to declare an instance of the EnumToStringConverter in XAML. It can be a local resource or declared in app.xaml to make it accessible everywhere.
<Window.Resources>
<my:EnumToStringConverter x:Key="DefaultEnumToStringConverter"/>
</Window.Resources>
Then use it like this:
Text="{Binding StatusMsg, Converter={StaticResource DefaultEnumToStringConverter}}"
Note the word "StaticResource" in the converter. That is the markup extension. This one tells WPF to go find the static resource with the key "DefaultEnumToStringConverter". WPF will search up the visual tree of the element looking for a resource with that key. If one isn't found it will check at the application level in app.xaml.
MarkupExtensions are the things at the beginning of an attribute enclosed in the {}, "x", "binding", "static", etc. They are what give WPF the ability to resolve the text attribute in to a useful object instance. You can create your own MarkupExtensions to do some pretty cool things.
In your particular example it is complaining because it is looking for a markup extension named "my", from the inner Converter={my:EnumToStringConverter}.

ComboBox binding works only one way with Color property

I'm implementing an ObservableCollection <-> DataGrid binding.
My class consists of a System.Windows.Media.Color field (named 'Color') and several strings.
My implementation in WPF of the Color column:
<DataGridTemplateColumn Header="Color" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Source={StaticResource ColorProperties}}"
SelectedItem="{Binding Path=Color, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Style="{StaticResource ComboBoxFlatStyle}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="1" Orientation="Horizontal">
<Rectangle Fill="{Binding}" Height="10" Width="10" Margin="2"/>
<TextBlock Text="{Binding}" Margin="2,0,0,0"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
And ColorProperties:
<ObjectDataProvider x:Key="ColorProperties" ObjectType="{x:Type color:ColorHelper}"
MethodName="GetColorNames"/>
The ColorHelper class (I'll try to find the OP for credit):
public static class ColorHelper
{
public static IEnumerable<string> GetColorNames()
{
foreach (PropertyInfo p
in typeof(Colors).GetProperties(
BindingFlags.Public | BindingFlags.Static))
{
yield return p.Name;
}
}
}
This works just fine, I can see the combo-box with all the colors:
Now I added a few objects to the ObservableCollection, and their respective fields are populated in the DataGrid. All except the Color.
The default Color is Black, but when I run the application, the ComboBox stays empty.
When I select a color from the ComboBox, the ObservableCollection changes accordingly. However if I change the object itself, the ComboBox stays with its original value.
For troubleshooting, I added
<DataGridTextColumn Header="Color" Binding="{Binding Color, UpdateSourceTrigger=LostFocus}"
Width="100"/>
This column gets populated with the string representation of the color, and when I change the value from either side, it changes accordingly.
This fact suggests that there's something missing in the ComboBox implementation.
Am I missing some sort of translation method? Seems weird since it actually works in one way (from ComboBox to object).
I've searched everywhere for a solution, without success.
EDIT:
I implemented Color<->String converter, still doesn't work..
public class StringToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Color content = (Color)value;
return content.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
string content = (string)value;
return (Color)ColorConverter.ConvertFromString(content);
}
}
WPF change:
<ComboBox ItemsSource="{Binding Source={StaticResource ColorProperties}}"
SelectedItem="{Binding Path=Color, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay,
Converter={StaticResource StringToColorConverter}}"
Style="{StaticResource ComboBoxFlatStyle}">
Any ideas?
Thanks!
The list bound to Combobox is a list of strings, whereas the actual object is not just a string. you need a converter that converts from string to your desired object.
Rest all seems fine, system dosent know how does string Black translates to Color Black
-- one way binding works because, color object knows how to get color from a string, that is why when we set Background="String" it get the corresponding object using FromName
OK i found out what was wrong. It looks like getting the actual name from a color is not that simple. ToString returns the hex string, and not the actual color name.
So I used the answer from http://www.blogs.intuidev.com/post/2010/02/05/ColorHelper.aspx to create the converter.
public class ColorToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Color KnownColor;
Color content = (Color)value;
Type ColorType = typeof(System.Windows.Media.Colors);
PropertyInfo[] ColorsCollection = ColorType.GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (PropertyInfo pi in ColorsCollection)
{
KnownColor = (Color)pi.GetValue(null);
if (KnownColor == content)
return pi.Name;
}
return String.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
string content = (string)value;
return (Color)ColorConverter.ConvertFromString(content);
}
}

How to implement a table that appears / expands when the "expand" button is clicked?

Is it better to build 2 different pages? Such that when a button is clicked, it leads to another page with the table? Or can we hide the table until the "expand" button is clicked? Is it better to present the table as a listbox? Thanks.
I think a converter is the way to go, like TerrenceJackson said!
In the DataGrid your Binding should look like this:
<CheckBox Content="Expand" Height="72" Name=MyExpandCheckbox IsChecked="False" />
<DataGrid Visibility="{Binding ElementName=MyExpandCheckbox, Path=IsChecked, Converter={StaticResource BoolToVisibleConverter}}"/>
You have to set the Name of your Button/Checkbox/... for the ElementName in the binding for the visibility-property.
Here is an example of a BoolToVisibilityConverter:
public class BoolToVisibilityConverter : IValueConverter
{
#region IValueConverter member
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (Boolean)value ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
i would'nt do it with two seperate pages.
You can use a simple expander and style it for your purpose. Here's a video how to use the expander: http://silverlight.net/learn/videos/all/silverlight-toolkit-creating-a-toolkit-expander/ and here's a simple tutorial http://www.c-sharpcorner.com/Resources/768/.
You could also use a simple toggle button and bind the visibility of the table (DataGrid or ListBox, whatever you want) with a converter to the checked state of the toggle button. Somehow like this:
<ToggleButton x:Name="myToggleButton" />
<DataGrid Visibility="{Binding ElementName, Path=IsChecked, Converter={StaticResource BoolToVisibleConverter}}"/>
The BoolToVisibleConverter is a class which implements IValueConverter (http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx).
I don't know your exact aim, but I guess the expander approach is good for you.
Hope this helps.
BR,
TJ

Wpf custom control template - relative font size

I am creating a custom WPF control that let's say for simplicity sake has a vertical stack panel with a "title" TextBlock, followed by a ContentPresenter. I want the font size for the "title" to be 5 Points LARGER than the size used in the content, which is inherited by whatever container the user places this control in.
How can I specify a font size in the control template for the header element using a relative value without exposing a property like "TitleFontSize" to the user? I want do "add 5".
I tried using a ScaleTransform on the header text block with mixed results (the text block scaled fine but the orientation was modified - I had the text right-justified and it moved "off the control" area when scaled). Also, I am not sure if scale transform would be approprite here.
A more generic way
Value converter
public class MathConverter : IValueConverter
{
public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
{
return (double)value + double.Parse( parameter.ToString() );
}
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
{
return null;
}
}
Converter Resource
<my:MathConverter x:Key="MathConverter" />
XAML
<TextBlock FontSize="{Binding
RelativeSource={RelativeSource AncestorType={x:Type Window}},
Path=FontSize,
Converter={StaticResource MathConverter},
ConverterParameter=2}" />
I did it with an IValueConverter as follows:
Created a class FontSizeConverter that derives from IValueConverter. The Convert method adds 10 to the value, and the ConvertBack method subtracts 10.
public class FontSizeConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (double)value + 12.0;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (double)value - 12.0;
}
#endregion
}
Next, I declaried an instance of this class in the XAML template for the control:
<Style.Resources>
<local:FontSizeConverter x:Key="fontSizeConverter"/>
</Style.Resources>
And Finnaly, the FontSize binding uses this converter applied to the inherited FontSize property:
<TextBlock FontSize="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=FontSize, Converter={StaticResource fontSizeConverter}}"
Grid.Row="0" Text="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=Date.Day}" HorizontalAlignment="Right" VerticalAlignment="Top" Padding="2" Margin="2" >
</TextBlock>
This works. But I still do not know if this is the correct answer. Let me know if there is a better way, or if this is appropriate.

Resources