IValueConverter uses the wrong culture with DateTime - wpf

Hi the below code is used to convert the DateTime format to current thread culture format
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is DateTimeOffset?)
{
var dto = (DateTimeOffset?)value;
return dto.Value.ToString("t", culture);
}
return null;
}
But the DateTimeFormat in culture parameter is not updating to the current system datetime format, instead it uses the fixed format like HH:mm tt for short time.
The workarond for this is to set the language from the current thread as below, which we have done in App.Xaml but still DateTimeFormat will have the default format.
// fixes culture-specific binding formatting. See this link: WPF Binding StringFormat Short Date String
this.Language = System.Windows.Markup.XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.IetfLanguageTag);
I have gone through some blogs on this and looks like its a bug in WPF. Some guys suggest not to rely on culture for DateTime as DateTimePicker should give a selected date formatted to the local thread culture. This works fine if we remove the culture parameter in ToString().
Please provide your suggestions or solution for this :)

Maybe you need to set the language also on the WPF controls
(also in App.xaml.cs)
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

Related

Wpf textbox converter to double in combination with updatesourcetrigger=propertychanged

In our project we have a WPF textbox that is bound to a double. There is a converter that allows in the convertback to for example use both "." and "," to as decimal points and in the convert method it formats the double to the n2 numeric format.
Here you can see a simplefied version of our converter:
public class DoubleConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || value.GetType() != typeof(double))
return null;
else
return ((double)value).ToString("n2");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return null
else
return Double.Parse(((string)value).Replace('.',','));
}
}
The textbox looks like this:
<TextBox Text="{Binding Path=Factor, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Width="500" Height="50" />
And the double property raises a propertychanged event:
public double Factor
{
get { return _factor; }
set
{
_factor = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Factor"));
}
}
This used to work fine in previous versions of WPF because the convert was'nt called when you were entering text. This behavior apparently has changed and now the convert method is called on every text entry, causing the double to be formatted when you type something.Even if you don't use formatting you have the problem of not being able to enter a decimal point.
This can be solve by not using UpdateSourceTrigger=Propertychanged, but we need this for validation. We implement validation by using the IDataErrorInterface. I know there is a ValidateWithoutUpdate method, but this doesn't work for validation using the IDataErrorInterface.
So what I basicly need is ConvertBack (and thus the validation) to happen OnPropertyChanged and the Convert to only happen OnLostFocus.
Is this possible? Or is there another solution for our problem?
Yes, the behavior change from .Net 3.5 to .Net 4.0, where it now sends source updates back to targets even if the update originated from the target. This SO post explains it a bit and provides a solution:
Why does binding setup behave differently in .NET 4 vs .NET 3.5
These are the options I've found so far for dealing with this:
Have the converter maintain the state of the input on ConvertBack and restoring it in Convert (suggested in link above)
Change backing data to strings, handle conversion in model
Create a custom control that handles this kind of numeric input similar to how a DateTimePicker works (it maintains a string and double representation of the data; displays the string, but is bound by the double)

ConverterParameter Usage

I have a basic question regarding the usage of ConverterParameter. In the sense - I can always create a collection of types in my viewmodel and pass it to the converter during Binding.
And then in my convert method - I can do multiple if check statements and return accordingly
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
}
So the question is what exactly are the scenarios of using a ConverterParameter which just justifies it usage.
Please note - I am not asking how to use a ConverterParameter - i have done that - more interested when to use it
Here's some of the cases where I used Converter parameter
I have a converter used by many user controls each user control
represents specific class type. I used converter parameter to hold
the class type so I can control the conversion behavior based on the
parameter type.
I have a converter that convert date to string. I used converter
parameter to define if It's Departure date or arrival date to return
single string in the required format

Is it Possible to Bind two Different resource values in the same textbox using Silverlight

i have two values firstname and lastname i want to display them together as firsname.lastname
how to right the binding path so that i can get both values is it possible to do such things??
There's not a direct way to do what you're asking.
Create a third property that returns the formatted value and fire a PropertyChanged event for it when either firstname or lastname change.
I would use 2 text boxes inside stack panel, o create a data template
A converter could be a good option here
for example it would make sense that you have a Person object in this case. For your textbox bind to the person object and pass it through a converter. the converter could take the values and return your combined string
something like the following
// this would be your convert function inside your converter that implements the IValueConverter interface
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Person p = value as p;
if (p != null)
{
return string.Format("{0},{1}", p.LastName,p.FirstName);
}
return string.Empty; //or you could show an error maybe...
}

WPF how to bind two observable collections of different but related types using a value converter?

I have a custom control with an observable collection(DP) holding a certain type objects. I want to bind it to another observable collection holding a different type objects in my VM. How do I do this?
Should I even be doing something like this?
Edit. Ofcourse the binding should work when elements in the collections are modified on either side.
Meleak's comment is correct, you should somehow transform one collection into another and sync them. Here is how I did it last time:
View (I've named it MyControl below) has property Items of type IEnumerable<Target>
DataContext has property Items of type IEnumerable<Source>
class CollectionsConverter : IValueConverter
{
public object Convert(object value, ...)
{
var source = (ObservableCollection<Source>)value;
var target = new ObservableCollection<Target>(source.Select(/* Convert items somehow /);
// subscribe to both target's and source's 'CollectionChanged' events
// and propagate them back and forth to another collection.
// Propagated events should have converted items of course
return target;
}
...
}
Then in XAML:
<MyControl Items="{Binding Items, Converter=CollectionsConverter}" />
Regarding converting each item - it can be either generic code which will dynamically determine how to convert Source to Target and vice versa or it should be a code which will know which exact types it will convert and how to convert them.
ValueConverters don't work the way you're describing, you have to create a new collection by-hand.
This doesn't answer your question directly, but in ReactiveUI (http://www.reactiveui.net), this scenario is quite easy:
var derivedColl = someCollection.CreateDerivedCollection(x => new SomeOtherClass(x));
Use your custom Converter class implementing IValueConverter
public class ObserverTypeConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//return your dependency type from here
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//return your view model type from here, this will get fired if your binding is two way
}
}

Using silverlight datepicker and timepicker together

I'm using the Silverlight DatePicker and TimePicker from the toolkit together to allow a user to select a date and time. They are bound to the same DateTime value on a business object behind the scences. This mostly works okay, except when the date component is changed the time component is wiped. This is kinda logical but probably not the behaviour the user wanted.
There's a couple of ways I could hack my way round this:
Store the date and time components in different values (not that hacky but a little anonying as I'm going to store the resulting value as one field in a db)
Try and fix up the time component when the SelectedDateChanged event fires (which does seem a very hacky solution)
I'd like to be able to tell the DatePicker control: just leave the time component when you change date. Am I hoping for too much?
I think, you can say DatePicker "Just leave the time component when you change date" using converter :). When you are binding DateTime to DatePicker converter stores value, and on ConvertBack returns without changes in Time part.
public class DateConverter : IValueConverter
{
private DateTime _original;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
_original = (DateTime)value;
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
DateTime date = ((DateTime) value);
return new DateTime(date.Year, date.Month, date.Day, _original.Hour, _original.Minute, _original.Second);
}
}
XAML:
<sdk:DatePicker SelectedDate="{Binding Date, Mode=TwoWay,
Converter={StaticResource dateConverter}}" />
<input:TimePicker Value="{Binding Date, Mode=TwoWay}"/>

Resources