2

I created an inline MultiBinding using this post as a reference. More specifically, I'm using Christian Myksvoll's answer for creating a custom binding. My class looks like this:

   public class MultiBinder : MultiBinding
   {

      public MultiBinder(BindingBase[] bindings, object converter)
      {
         foreach (BindingBase b in bindings)
         {
            Bindings.Add(b);
         }

         Converter = converter as IMultiValueConverter;
      }

      public MultiBinder(BindingBase b1, BindingBase b2, object converter)
      {
         Bindings.Add(b1);
         Bindings.Add(b2);

         Converter = converter as IMultiValueConverter;
      }

      public MultiBinder(BindingBase b1, BindingBase b2, BindingBase b3, object converter)
      {
         Bindings.Add(b1);
         Bindings.Add(b2);
         Bindings.Add(b3);

         Converter = converter as IMultiValueConverter;
      }

      public MultiBinder(BindingBase b1, BindingBase b2, BindingBase b3, BindingBase b4, object converter)
      {
         Bindings.Add(b1);
         Bindings.Add(b2);
         Bindings.Add(b3);
         Bindings.Add(b4);

         Converter = converter as IMultiValueConverter;
      }
   }

I added the first array constructor just to see if I could make it handle an unknown number of bindings, but I couldn't get the call to work. So, I removed it, and now I'm trying to use the 3 value constructor :

<MyControl IsEnabled="{util:MultiBinder 
                         {Binding Path=IsRequestedPriceControlEnabled}, 
                         {Binding Path=IsIndicative}, 
                         {StaticResource MultiBoolConverter}
                      }" />

It's giving me this error:

Cannot set MultiBinding because MultiValueConverter must be specified.

The converter I'm providing implements IMultiValueConverter and is being used without problem in a style block elsewhere. I can't use it in a style block for this purpose due to the sheer number of control types and variable conditions required.

Class Declaration: public class MultiBoolToBoolConverter : IMultiValueConverter
Resource: <util:MultiBoolToBoolConverter x:Key="MultiBoolConverter" />

The only thing I can figure is that it doesn't recognize that the 3rd parameter is the converter. I've tried tinkering with the IsEnabled content to explicitly set Converter like Discord's example (along with trimming down the class to only have a single constructor with 2 parameters), but that didn't work, either. That gives this error:

Unknown property 'Converter' for type 'MS.Internal.Markup.MarkupExtensionParser+UnknownMarkupExtension' encountered while parsing a Markup Extension.

My Question:

Has anyone made an inline multi-binding like this and know what I'm doing wrong?

Note: I'm using .NET 4.6, so I can use any other functionality if needed.


EDIT:

I still get the "Cannot set [...]" error above in the designer even with Evk's defaulting to null and using a dummy converter. But, it does run. I'm testing it with this:

CommandParameter="{util:MultiBinder {Binding Path=IsExpiriesComboBoxEnabled}, {Binding Path=IsIndicative}, {StaticResource MultiBoolConverter}}"

If I put a breakpoint in the MultiBinder, it goes into the 3 parameter overload (b1,b2,converter) correctly, and I can see the Converter being set to the MultiBoolConverter. So, I don't know why it's still giving the designer error.

SOLUTION:

The problem was a really, really stupid one. At some point after migrating the solution from VS2008 to VS2015, a XAML designer gave me an error or something and suggested disabling code execution, so I did. So, using the inline multibinder was confusing it since the converter wasn't being passed in. I had a hard time finding where to turn code execution back on, but once I did, it worked. So, the inline multibinding DOES work -- if it is being executed.

If you run into the same problem, here's the button that eluded me:

Enable Project Code

Community
  • 1
  • 1
Chris Fannin
  • 1,284
  • 1
  • 10
  • 16

2 Answers2

1

First, your MultiBinder does work, as you provided it in your question without any modifications. It does not produce any errors at runtime and correct constructor is called.

Problem is WPF designer, which is known to be quite buggy and produce false errors in many cases, like this one. Of course you can just ignore that "error" you see in designer but it's quite annoying plus you can miss real errors if you would ignore them.

Instead, we can find what exactly designer does wrong and try to fix that. Error message provides a clue that converter which is passed in design mode to your constructor is null. Then we can fix it like this:

public class MultiBinder : MultiBinding {
    public MultiBinder(BindingBase b1, BindingBase b2, object converter = null) {
        Bindings.Add(b1);
        Bindings.Add(b2);

        Converter = converter as IMultiValueConverter;
        CheckConverter();
    }

    public MultiBinder(BindingBase b1, BindingBase b2, BindingBase b3, object converter) {
        Bindings.Add(b1);
        Bindings.Add(b2);
        Bindings.Add(b3);

        Converter = converter as IMultiValueConverter;
        CheckConverter();
    }

    public MultiBinder(BindingBase b1, BindingBase b2, BindingBase b3, BindingBase b4, object converter) {
        Bindings.Add(b1);
        Bindings.Add(b2);
        Bindings.Add(b3);
        Bindings.Add(b4);

        Converter = converter as IMultiValueConverter;
        CheckConverter();
    }

    private void CheckConverter() {            
        if (Converter == null && DesignerProperties.GetIsInDesignMode(new DependencyObject())) {
            // if we are in design mode - feed dummy converter which cannot be called to wpf designer
            Converter = new DummyConverter();
        }
    }

    private class DummyConverter : IMultiValueConverter {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
            throw new NotSupportedException();
        }

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

This binder does not produce errors both is designer and in runtime.

Evk
  • 98,527
  • 8
  • 141
  • 191
  • I don't know why, but mine still gives the converter error during design time and build. But, the application does run. I'm looking for a setup that will let me confirm if it works correctly during runtime. Some of the boolean values are outside of my control at the moment as they come from the server. – Chris Fannin May 06 '16 at 18:31
  • Well I verified that code above fixes the problem. If it does not for you - provide more code and we can figure it out. – Evk May 06 '16 at 18:58
  • I think I know what the problem is. Sometime earlier after migrating to VS2015, it gave me a message about disabling code execution due to errors. Now it doesn't run converters, etc, on ANY designer. So, that might be the cause. I'm trying to figure out how to turn it back on. That will also let me find what needs design-time defensive coding. – Chris Fannin May 18 '16 at 17:52
  • Found it. Really tiny button under the designer "Enable project code". Guess what? Error went away. – Chris Fannin May 18 '16 at 18:12
  • Glad that you have figured it out finally. – Evk May 18 '16 at 18:14
-2

Please refer the below code..

<MyControl.IsEnabled>
      <util:MultiBinder Convertor="{StaticResource MultiBoolConverter}" >
          <Binding Path ="IsRequestedPriceControlEnabled"/> 
          <Binding Path ="IsIndicative"/> 
     </util:MultiBinder>
  </MyControl.IsEnabled>   
Peekay
  • 441
  • 3
  • 10
  • 25
  • I'm trying to avoid extended notation like that. It's a custom tab content control with A LOT of stuff going on. The XAML is 49KB, and the code-behind is 23KB. Also, the controls have a bunch of other property bindings (most have over 10 each), etc, so I'm trying to keep each one on a single line. My example was just to show how I'm trying to set the one property. Note: The downvote(s) aren't mine. – Chris Fannin May 05 '16 at 19:17
  • Oh ok i think i understood it wrong. You should downvote if the answer is not helpful :) – Peekay May 05 '16 at 19:34
  • No problem. I'm not going to downvote because even though it didn't directly apply to my question, someone else may find it useful. :-) – Chris Fannin May 05 '16 at 19:38
  • How could this be useful when the question explicitly asks for "inline multi-binding". Without the inline part, it would be an ordinary MultiBinding without any need for a specialized/derived class. This post just shows the standard XAML syntax for MultiBinding on a (then redundantly) derived MultiBinding class, and is hence not an answer to the question. IMO it should be deleted to avoid the impression that the question already has an answer. – Clemens May 05 '16 at 21:02
  • In case you're curious: My original approach worked. It was the Project Code execution that was missing. I edited my post to show the solution. As a side note: I also don't downvote because of the rep penalty on me. ;-) – Chris Fannin May 18 '16 at 19:08