Ehsan Keshavarzian Ehsan Keshavarzian - 4 months ago 18
C# Question

How to use StringFormat in MultiBinding?

I have the following code:

<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}{1}">
<Binding Path=".[ServerName]" TargetNullValue=""/>
<Binding Path=".[InstanceName]" TargetNullValue="" StringFormat="{}\\{0}"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>


but the result I get is "ServerNameInstanceName" instead of "ServerName\InstanceName"

Answer

StringFormat is ignored if the target of the binding is not typed as String. Therefore, the StringFormat on the MultiBinding will be used, because TextBlock.Text is String (it wouldn't work if you were binding to Label.Content, because Label.Content is Object -- a common complaint). The inner one, the binding to .[InstanceName], doesn't have a target that's typed as String, because MultiBindings must accept values of any type. So that StringFormat is ignored.

The following works.

<TextBlock>
  <TextBlock.Text>
    <MultiBinding StringFormat="{}{0}\{1}">
      <Binding Path=".[ServerName]" TargetNullValue=""/>
      <Binding Path=".[InstanceName]" TargetNullValue="" />
    </MultiBinding>
  </TextBlock.Text>
</TextBlock>

If you did it your way in order to eliminate the backslash in cases where .[InstanceName] is null, you've got a problem. I would write a multivalue converter to insert the backslash, or not, and skip StringFormat. There's no way to get StringFormat to do what you need it to do here. It's just not smart enough.

C#

public class ServerInstance : MarkupExtension, IMultiValueConverter
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    public object Convert(object[] values, Type targetType, 
        object parameter, CultureInfo culture)
    {
        var server = $"{values[0]}0";
        var instance = $"{values[1]}";

        if (instance == "")
            return server;

        if (server == "")
            return "";

        return $"{server}\\{instance}";
    }

    public object[] ConvertBack(object value, Type[] targetTypes, 
        object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

XAML

<TextBlock>
  <TextBlock.Text>
    <MultiBinding Converter="{local:ServerInstance}">
      <Binding Path=".[ServerName]" />
      <Binding Path=".[InstanceName]" />
    </MultiBinding>
  </TextBlock.Text>
</TextBlock>