0

In the following xaml sample source, I am trying to bind the A property in the SampleViewModel to the B property, which is a DependencyProperty in the SampleConverter.

However, when I do this, I get a XAML bind error and the Data Context is displayed as null.

I know it is possible to get the Data Context using x:Name, but is it possible to get the Data Context without using x:Name?

<Window
    x:Class="WpfApp1.BindPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfApp1"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Window.DataContext>
        <local:SampleViewModel />
    </Window.DataContext>

    <StackPanel>
        <StackPanel.Height>
            <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=Self}">
                <Binding.Converter>
                    <local:SampleConverter B="{Binding A}" />
                </Binding.Converter>
            </Binding>
        </StackPanel.Height>
    </StackPanel>

</Window>

I should mention that with RelativeSource I could not get other than myself (in this case, other than the SampleConverter).

cjk
  • 1
  • 1
  • The converter is a simple value of the Binding.Converters property (collection). It is not part of the visual tree. It therefore does not inherit any DataContext. That's why the DataContext returns NULL on inspections and the Binding can't resolve. Your problem is usually solved by using a MultiBinding. It allows to bind a target property (for example StackPanel.Height) to multiple source properties (for example StackPanel.ActualHeight and SampleViewModel.A). – BionicCode Jan 24 '23 at 17:32

1 Answers1

0

That isn't how you use converters.

I don't know what local:SampleConverter is exactly but it has a property B

  B="{Binding A}"

The binding provides the value, you may also bind a command parameter

Here's an example

 <Image Name="GridImage" 
        Visibility="{Binding AppSettings.ShowGrid
                   , Converter={StaticResource BooleanToVisibilityConverter}}"
                                   />

This is going to set the Visibility property, the binding is to AppSetting.ShowGrid which is in the datacontext rather than converter. The BooleanToVibilityConverter is taking a bool from ShowGrid and converts it to a Visibility.

If you wanted to bind multiple properties then you can use a multiconverter with a multibinding.

    <MultiBinding Converter="{ui:AllMultiplyMultiConverter}" StringFormat="{}{0:n0}">
             <Binding Path="Value" ElementName="turnTime"/>
             <Binding Path="MoveRate"/>
    </MultiBinding>

A multiconverter receives an array object[] for those values.

Since markup extension and ivalueconverter are not dependency objects you would need to reference the parent object to use a dependency property.

You could add dependency properties to your window and reference them in a markup extension that's also a valueconverter.

Consider this value converter that's also a markup extension.

public class AddConverter : MarkupExtension, IValueConverter
{
    public double ValueToAdd { get; set; }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double bound = (Double)value;
        return bound + ValueToAdd;
    }

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

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
}

ValueToAdd is just a property, you can't bind it.

You can get a reference in that ProvideValue to the parent dependency object. Hence window or usercontrol.

   IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;

That target is your control and you can grab dependency properties off that. You could (say) set ValueToAdd in there and use it in the converter. You could cast the datacontext of the targetobject and read values off properties directly.

This is a very complicated approach. I've never had the need for this myself and I would recommend multibinding and multiconverter instead.

Andy
  • 11,864
  • 2
  • 17
  • 20