views:

1588

answers:

2

Is there an issue with databinding in WPF when you bind to the current source (Path=".") and using a converter? The two way binding doesn't seem to work in this situation.

I know I could change the path, but I want to be able to pass the "Name" value to the converter.

I can't get the following example to work:

<Window x:Class="WpfTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:WpfTest"
Title="Window1" Height="600" Width="600">

<Window.Resources>
    <l:Person x:Key="myDataSource" Name="Cam"/>

    <l:TestConverter x:Key="converter" />
</Window.Resources>

<StackPanel>
    <StackPanel.DataContext>
        <Binding Source="{StaticResource myDataSource}"/>
    </StackPanel.DataContext>

    <TextBox>
        <TextBox.Text>
            <Binding 
                Path="." 
                UpdateSourceTrigger="PropertyChanged"  
                Converter="{StaticResource converter}" 
                ConverterParameter="Name" 
                />
        </TextBox.Text>
    </TextBox> 
    <TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</Window>

class TestConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return Reverse(value, parameter);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return Reverse(value, parameter);
    }

    private static object Reverse(object value, object parameter)
    {
        if (value == null)
            throw new ArgumentNullException("value", "value is null.");
        if (parameter == null)
            throw new ArgumentNullException("parameter", "parameter is null.");

        Person p = (Person)value;

        if (parameter.ToString() == "Name")
        {
            StringBuilder sb = new StringBuilder();
            for (int i = p.Name.Length - 1; i >= 0; i--)
            {
                sb.Append(p.Name[i]);
            }

            return sb.ToString();
        }

        throw new NotImplementedException();
    }
}

public class Person:INotifyPropertyChanged
{
    private string name;
    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;

            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("Name"));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}
A: 

Cameron,

I'm not really sure from this what you're trying to do.

You're Binding to "." which means you need to be able to convert from string to Person and Person to string, but your implementation doesn't do this. But then you'd be changing the instance the Resource myDataSource is pointing to. I'm not sure you can do that.

If you just want to modify the string, why wouldn't you specify the Binding.Path as "Name" and supply a converter that did what you want to the string?

Sam

Sam Meldrum
You're right, the ConvertBack probably won't work. Right now I'd just be happy if it threw an exception, but the binding won't even call the method.
Cameron MacFarland
As for Path=Name, I want to be able to pass that in as a parameter because depending on the type bound the property could be name, fullname, surname, etc, and I want "Name" to look up the type and return the correct value.
Cameron MacFarland
I think you might be better off constructing your solution a little differently. E.g. Different controls binding to the properties with specific converters and changing the visibility of those controls - you could bind the visibility of the control to some property to change which is displayed.
Sam Meldrum
A: 

You can't use two way binding with the current source (with or without converters).

Think about it without converters for a minute, when binding to the current source you don't have a property to set - except the DataContext itself who is often derived from another source (for example it may be set to a list item by an ItemControl) so there's no point overriding teh DataContext property.

So WPF won't try to bind changes back to the source because it can't change the source.

Now, a custom ValueConverter can obviously do anything, including things that are not just value conventions but are useful in your specific situation, but a value converter is just supposed to convert the value type - and the system has nothing to do with the result of the value converter in this case, it has nowhere to assign it to - so there's no point in calling the value converter.

Nir