using IValueConverter with current DataContext in two-way binding
Asked Answered
D

3

6

I'm having issues with a converter i'm using to convert between a string and our timeformat. The converter itself works fine and is implemeneted like this:

    [ValueConversion(typeof(string), typeof(SimpleTime))]
    public class StringToSimpleTimeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // convert from string to SimpleTime and return it
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // convert value from SimpleTime to string and return it
        }
    }

The XAML that uses the converter includes the converter itself in the usercontrol.resources like this:

<converter:StringToSimpleTimeConverter x:Key="stringToSimpleTimeConverter"/>

If the property is encountered (I'm using the datagrid from the wpf toolkit in the background) the datatemplate for editing the simpletime is used:

<DataTemplate x:Key="SimpleTimeEditingTemplate">
        <TextBox Text="{Binding, Converter={StaticResource stringToSimpleTimeConverter}, Mode=TwoWay}"/>
</DataTemplate>

The problem i'm encountering is that the converter needs to have a path specified in the binding if it is a twoway converter (and i need it in both directions), but the property i want to set is already the current DataContext - What Path can i specify for that then?

The only workaround i could think of is introduce a dummy property in the SimpleTime that just gets the current SimpleTime or sets it.

public class SimpleTime
{
    ...
    public SimpleTime Clone
    {
        get { return new SimpleTime(_amount, _format); }
        set { this._amount = value._amount; this._format = value._format; }
    }
}

and bind to that one via

 <TextBox Text="{Binding Clone, Converter={StaticResource stringToSimpleTimeConverter}, Mode=TwoWay}"/>

that works fine but isn't really a suitable solution, especially if i need converters for more times...

any help is appreciated cheers, manni

Deuno answered 10/12, 2010 at 8:37 Comment(0)
C
5

I think you can workaround it like this

<TextBox Text="{Binding Path=DataContext,
                        RelativeSource={RelativeSource Self},
                        Converter={StaticResource stringToSimpleTimeConverter}, 
                        Mode=TwoWay}"/>
Concern answered 10/12, 2010 at 8:55 Comment(5)
i have tried a similar approach using a parent usercontrol for the textbox and binding to it's datacontext. The IValueConverter gets called correctly to convert the string to simpletime and back to display the string in the control, but the set for the simpletime property in my datastructure never gets called - does anyone know how this can happen?Deuno
@manni: I made a test-app with this and for me it seems to be working just fine. It binds to its own DataContext so I see no reason for it not to work. Are you sure your ConvertBack method is never called?Concern
thanks for the effort. i think that what i mean to say was not clear enough: my convertback and convert methods are called if i change the value in the gui, that's working fine. but the property setter of the property i'm setting (the simpletime property) doesn't get called (breakpoint not triggered). i'll have a look into that now, thanks very much for your help, i really appreciate thatDeuno
i've built another sample, your approach is working fine when using it directly. i seem to have a bug somewhere using that in a datatemplate or the datagridcolumn. thanks again for the helpDeuno
Why not just "{Binding Converter={StaticResource stringToSimpleTimeConverter}, Mode=TwoWay}"? I.e., without the comma.Clubby
B
0

Instead of introducing a dummy property into your class, why not create a container class like the following:

public class Container
{
    public Object DataItem { get; set; }

    //...
}

and use it like:

<TextBox Text="{Binding DataItem, Converter={StaticResource stringToSimpleTimeConverter}, Mode=TwoWay}"/>

This will not corrupt/mutate your existing class and still allow you to do what you wish to do.

Birdwell answered 10/12, 2010 at 8:54 Comment(4)
good idea, but not really feasible for my datastructures. i don't want to put every property into a container, and the parent List object is directly bound to the datagrid, which chooses for each of the properties in the class a column to display and edit, which will have the property directly as datacontext.Deuno
I think what you are doing is setting each property as a DataContext of a Control and bind them using {Binding} without specifying a path. If this is what you are doing, it is wrong. You should set DataContext of a parent control and all child controls derive it. And only use bindings using different paths in child controls.Birdwell
i thought that the datagridcolumns worked that way. the datatemplate i use for a gridcell in the datagrid to show or edit cannot have the datacontext set to the complete structure, cause that would mean it has to now the name of the attribute it should apply to. what i want is to apply the datatemplate to the specific type without knowing it's name, so my codebehind sets the binding for the datagridcolumn and sets its datatemplates for showing and editing. the datatemplate itself is appled to more than one propertyname, depending on the types of the propertiesDeuno
after lots of trying and thinking, i came to your conclusion. it's wrong after all, because it cannot switches out the whole property that it's binding on, instead of switching the property in the parent datacontext. i'll have to change my design to incorporate that. thanks for your help, pity i can't mark both answers as correct, thanks againDeuno
D
0

I know it's old question, but in case somebody stumbles upon this, correct Path here would be Path=.

<DataTemplate x:Key="SimpleTimeEditingTemplate">
        <TextBox Text="{Binding Path=., Converter={StaticResource stringToSimpleTimeConverter}, Mode=TwoWay}"/>
</DataTemplate>
Deen answered 27/4, 2018 at 12:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.