Using FindResource in an IValueConverter - c#

I have this value converter which converts a number to a brush color. What I need to do is to change the line return Brushes.Red; into return (Brush)FindResource("PrimaryHueMidBrush");, so I can return the color of the main theme. The problem is that I don't know how to declare (Brush)FindResource("PrimaryHueMidBrush");. Any help is welcome. Thank you in advance.
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double.TryParse(value.ToString(), out double val);
if (val == 1)
{
return Brushes.Red;
}
else if(val == 0.5)
{
return Brushes.MediumVioletRed;
}
else if(val==0)
{
return Brushes.Transparent;
}
else
{
return Brushes.Transparent;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}

Instead of calling FindResource in the converter, you'd better add one or more properties for the dynamic Brushes:
public class YourConverter : IValueConverter
{
public Brush FirstBrush { get; set; }
public Brush SecondBrush { get; set; }
public object Convert(
object value, Type targetType, object parameter, CultureInfo culture)
{
double val = (double)value;
if (val >= 1)
{
return FirstBrush;
}
if (val >= 0.5)
{
return SecondBrush;
}
return Brushes.Transparent;
}
public object ConvertBack(
object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
You would declare it in the Resources of your Application or Window like this:
<local:YourConverter x:Key="YourConverter"
FirstBrush="{StaticResource PrimaryHueMidBrush}"
SecondBrush="MediumVioletRed"/>

To access FindResource you need a FrameworkElement so the best way to do this would probably be to use a MultiValueConverter instead and pass the element that uses the converter as a second value.
Converter:
public class WhateverThisIsCalledConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
// Insert type- and sanity-checks here
double val = (double)values[0];
FrameworkElement callingElement = (FrameworkElement)values[1];
if (val >= 1)
{
return callingElement.FindResource("PrimaryHueMidBrush");
}
if (val >= 0.5)
{
return Brushes.MediumVioletRed;
}
return Brushes.Transparent;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return Enumerable.Repeat(DependencyProperty.UnsetValue, targetTypes.Length).ToArray();
}
}
Usage in XAML:
<Window.Resources>
<local:WhateverThisIsCalledConverter x:Key="Converter"/>
<SolidColorBrush Color="Red" x:Key="PrimaryHueMidBrush"/>
</Window.Resources>
<Grid>
<Grid.Background>
<MultiBinding Converter="{StaticResource Converter}">
<Binding Path="Value"/>
<Binding RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</Grid.Background>
</Grid>
Couple of notes on your current implementation:
Try avoiding == on doubles, they are not infinitely precice.
You don't need all those elses when you return in the if before.
The ConvertBack method should be implemented (Free choice of other Exceptions, Binding.DoNothing and DependencyProperty.UnsetValue).
If you know your value is a double, simply cast it instead.

Related

How to keep the original value unchanged in MultiBinding

I have the following multi-binding for my TextBlock
<Multibinding Converter="{StaticResource myconv}">
<Binding Path="Property1" />
<Binding Path="Property2" />
<Binding Path="Property3" />
</Multibinding>
Here is my converter code
public class PropertiesSelectorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return values.Where(v => v != null).FirstOrDefault();
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Problem
Now what I would like to do here is when all of the Property1, Property2 and Property3 are null, I want TextBlock to retain its original value. How do I accomplish this ?
You can use the special value of Binding called Binding.DoNothing:
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var value = values.Where(v => v != null).FirstOrDefault();
return value == null ? Binding.DoNothing : value;
}

FormatString on WPF-DataGrid has no effect

i have a small problem with FormatString in my WPF-DataGrid. I use DataGridTextColumn for the column. My DataSource is a IList<IDictionary<string, string>>
My problem is, that if i set StringFormat, it doesn't have any effect on the column.
This is my binding code:
cColumn.Binding = new Binding("[" + Config.InternName.ToLower() + "]");
And this is how i set my FormatString:
#region [Date-Time Formating]
if (Config.DateTimeFormat.Trim() != "")
{
string cDateTimeFormat = Config.DateTimeFormat.Trim();
(cColumn.Binding as Binding).StringFormat = cDateTimeFormat;
}
#endregion
I have tried a lot DateTime-StringFomrats, but nothing solve my problem.
Thank you!
Here is my solution:
I can't simple use FormatString, without binding a datetime. So i wrote an IValueconverter:
public class StringDateTimeValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
DateTime cOutDateTime = DateTime.Now;
if (DateTime.TryParse(value.ToString(), out cOutDateTime))
{
return cOutDateTime;
}
else
{
return DependencyProperty.UnsetValue;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.ToString();
}
}

Converter cannot be applied to a property that expects the type System.Windows.Data.IValueConverter

I am having a problem in my WPF app that I do not quite understand. I am trying to bind a fill to a different color depending on the value of a certain property.
Here are the snippets involved:
public class GeoLocations
{
private static ObservableCollection<Bus> _locations = new ObservableCollection<Bus>();
public static ObservableCollection<Bus> locations
{
get { return _locations; }
set
{
_locations = value;
}
}
.
.
.
}
public class Bus : INotifyPropertyChanged
{
private double _VSAI;
public double VSAI
{
get
{
return _VSAI;
}
set
{
_VSAI = value;
OnPropertyChanged(new PropertyChangedEventArgs("VSAI"));
}
}
public class VsaiToColorConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double vsai = (double)value;
if (vsai < App.Settings.medVSAI)
return Brushes.Green;
if (vsai >= App.Settings.medVSAI && vsai <= App.Settings.maxVSAI)
return Brushes.Yellow;
if (vsai > App.Settings.maxVSAI)
return Brushes.Red;
return Brushes.Transparent;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then in my xaml I have the following:
in my resources I have
<local:GeoLocations x:Key="geolocs"/>
and then I have a map
<ig:GeographicProportionalSymbolSeries x:Name="ProportionalSeries"
LongitudeMemberPath="Longitude"
LatitudeMemberPath="Latitude"
ItemsSource="{Binding Source={StaticResource geolocs}, Path=locations}"
>
<!-- custom marker template for GeographicProportionalSymbolSeries -->
<ig:GeographicProportionalSymbolSeries.MarkerTemplate>
<DataTemplate>
<Ellipse x:Name="RootElement" Width="10" Height="10"
Stroke="DarkGray"
Opacity=".8"
StrokeThickness="0.5"
Fill="{Binding Path=Item.VSAI, Converter={StaticResource VSAIConverter}}">
</Ellipse>
</DataTemplate>
</ig:GeographicProportionalSymbolSeries.MarkerTemplate>
But the error I'm getting is on the FILL=..... above. I'm hoping this is an easy fix. I'm just a little too new still to understand how to fix this and what this error means.
Your converter needs to implement the IValueConverter interface. You've implemented the two methods but you omitted the IValueConverter interface so as far as the CLR is concerned, you just have a class that happens to have the same methods as IValueConverter but isn't actually implementing it.
public class VsaiToColorConverter : IValueConverter
You generally want to handle null value cases as well
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if(value == null) return Brushes.Transparent; //or null
double vsai = (double)value;
//..
}

How do I implement a CollectionLengthToVisibility converter?

I want to implement a converter so that certain XAML elements only appear/disappear if there are items in an ObservableCollection.
I have referenced How to access generic property without knowing the closed generic type but cannot get it to work with my implementation. It build and deploys OK (to Windows Phone 7 emulator and device) but does not work. Moreover Blend throws an exception and will no longer render the page,
NullReferenceException: Object reference not set to an instance of an
object.
Here is what I have so far,
// Sets the vsibility depending on whether the collection is empty or not depending if parameter is "VisibleOnEmpty" or "CollapsedOnEmpty"
public class CollectionLengthToVisibility : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo cultureInfo)
{
// From https://stackoverflow.com/questions/4592644/how-to-access-generic-property-without-knowing-the-closed-generic-type
var p = value.GetType().GetProperty("Length");
int? length = p.GetValue(value, new object[] { }) as int?;
string s = (string)parameter;
if ( ((length == 0) && (s == "VisibleOnEmpty"))
|| ((length != 0) && (s == "CollapsedOnEmpty")) )
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo cultureInfo)
{
return null;
}
}
Here is how I referenced the converter on Blend/XAML
<TextBlock Visibility="{Binding QuickProfiles, ConverterParameter=CollapsedOnEmpty, Converter={StaticResource CollectionLengthToVisibility}}">Some Text</TextBlock>
I would use the Enumerable.Any() extension method. It will work on any IEnumerable<T> and avoids you having to know what sort of collection you're dealing with. Since you don't know T you can just use .Cast<object>()
public class CollectionLengthToVisibility : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo cultureInfo)
{
var collection = value as System.Collections.IEnumerable;
if (collection == null)
throw new ArgumentException("value");
if (collection.Cast<object>().Any())
return Visibility.Visible;
else
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo cultureInfo)
{
throw new NotImplementedException();
}
}

Getting specific object out of public class in silverlight

Hey guys i have this converter class :
public class InboxItemValueConverters : IValueConverter
{
public object Convert(object value, System.Type targetType,
object parameter, CultureInfo culture)
{
int urgency = (int)value;
Brush brush = new SolidColorBrush();
if (urgency == 0)
{
brush = new SolidColorBrush(Colors.Green); }
else if (urgency == 1)
{
brush = new SolidColorBrush(Colors.Yellow);
}
else if (urgency == 2)
{
brush = new SolidColorBrush(Colors.Red);
}
return brush;
}
public object ConvertBack(object value, System.Type targetType,
object parameter, CultureInfo culture)
{
return null;
}
public object ConvDateToShort(object value, System.Type targetType,
object parameter, CultureInfo culture)
{
DateTime DT = (DateTime)value;
return DT.ToShortDateString();
}
public object Convdateback(object value, System.Type targetType,
object parameter, CultureInfo culture)
{
return null;
}
}
and this is how i referenced it and used it the first time :
<src:InboxItemValueConverters x:Key="converttocolor" />
<Canvas Background="{Binding Urgency, Converter={StaticResource converttocolor}}"
no in the class,as you guys can see i have a date converter in there? how would i go around getting to that object through the xaml? want to convert date in another control, from same class
new xaml :
Text="{Binding DocDate , Converter={StaticResource converttocolor}}"
thanks in advance!
i am using visual studio 2012/windows phone 8/c#/silverlight
You have to move your date converter out of the colorconverter class into it's own class
public class DateValueConverter : IValueConverter
{
public object Convert(object value, System.Type targetType,
object parameter, CultureInfo culture)
{
DateTime DT = (DateTime)value;
return DT.ToShortDateString();
}
public object ConvertBack(object value, System.Type targetType,
object parameter, CultureInfo culture)
{
return null;
}
}
Then declare it at the top like you did your color converter and then change the converter to point to the date converter's key
//This needs to be declared below the colorconverter resource
<src:DateValueConverter x:Key="dateConverter" />
Text="{Binding DocDate , Converter={StaticResource dateConverter}}"

Categories

Resources