0

If you know what attached property is, then imagine a case where you need to supply 2 or more of them altogether (here is an example) and only if all of them are set something will happens.

This sounds like calling a method with parameters to me, therefore a tittle.

Does anyone tried anything like this? I'd imagine it can also solve my current issue with such ugly looking workaround (having 10x times of 3 property):

<TextBox local:DynamicBinding.Property1="{Binding IsCheckedPath}"
         local:DynamicBinding.Source1="{Binding IsCheckedSource}"
         local:DynamicBinding.Target1="IsChecked"
         local:DynamicBinding.Property2="{Binding WidthPath}"
         local:DynamicBinding.Source2="{Binding WidthSource}"
         local:DynamicBinding.Target2="Width"
         local:DynamicBinding.Property3="{Binding TextPath"
         local:DynamicBinding.Source3="{Binding TextSource}"
         local:DynamicBinding.Target3="Text" ... />

Ideally I'd like something like this

<TextBox IsChecked="{Binding Path={Binding IsCheckedPath}, Source={Binding IsCheckedSource}}"
         Width="{Binding Path={Binding WidthPath}, Source={Binding WidthSource}}"
         Text="{Binding Path={Binding TextPath}, Source={Binding TextSource}}"

Or maybe even more brief, any ideas?

Community
  • 1
  • 1
Sinatr
  • 20,892
  • 15
  • 90
  • 319
  • Have your heard of [MultiBinding](https://blog.csainty.com/2009/12/wpf-multibinding-and.html) ? – Nawed Nabi Zada Feb 06 '17 at 10:39
  • why don't you simply define `Path={Binding TextPath}` like `Path=BindingTextPath` with a *switch* property of the VM? –  Feb 06 '17 at 10:39
  • @NawedNabiZada, yep, do you think it would looks better? Add to it having to write converter for *each* case or is it not required? – Sinatr Feb 06 '17 at 10:40
  • @user1892538, what you mean as "*switch* property"? I was thinking about making binding proxy (View <---> VM proxy <---> Model real property), but haven't tried it, nor sure if it's better. Can you show it as an answer (if it works, it's the answer, we will see how good it is)? – Sinatr Feb 06 '17 at 10:43
  • @Sinatr regarding a possible "switch property": before I write my version, what about [this](http://stackoverflow.com/a/13525335/6996876) answer? –  Feb 06 '17 at 10:47
  • @user1892538, that won't work, it's only one way (from VM to View) and what if path (source property) can be one of hundred properties? In my specific case idea is to supply binding via VM, but in fact editing value in View is changing/getting updates from Model property. So two-way binding is a minimum requirement. – Sinatr Feb 06 '17 at 10:52
  • I don't really know what you want to achieve, but it seem like you are trying to invent the wheel again. You might have to write some converters, but why is that a problem ? – Nawed Nabi Zada Feb 06 '17 at 10:52
  • @Sinatr I can easily manage to make it two-way... but if you have tons of props, I fail to see what kind of simplification do you expect –  Feb 06 '17 at 10:54
  • @user1892538, *"I can **easily** manage to make it two-way"* - I'd like to see how you'll do it ;) Again, VM has source (some model) and property name from it and View has to bind two-way to it. – Sinatr Feb 06 '17 at 11:00
  • @NawedNabiZada, can you show solution with converter and multibinding? Perhaps I don't understand what you mean. I don't like (1) to define 30 attached properties instead of.. lets say *markup extension*, as well as the (2) xaml syntax of it. Can you improve any? Without sacrificing reusability of course. – Sinatr Feb 06 '17 at 11:05
  • I have to understand your question correctly. You want to binding to some properties in your VM and if all of them are NOT null something should happen ? – Nawed Nabi Zada Feb 06 '17 at 12:13

1 Answers1

0

Ok, so instead of your ideal binding

Text="{Binding Path={Binding MyText}, Source={Binding MySource}}"

I'd suggest to use a switch property

Text="{Binding BindingMyText}"

that could be implemented with a ViewModel visitor (it looks more complicated but it's done on purpose to make illegal states unrepresentable)

internal abstract class IPropVisitor<A>
{
    internal abstract A bindingMyText(ModelA source);
    internal abstract void bindingMyText(ModelA source, A val);
    internal abstract A bindingMyText(ModelB source);
    internal abstract void bindingMyText(ModelB source, A val);
}

internal class ViewModelVisitor : IPropVisitor<string>, INotifyPropertyChanged
{
    internal ViewModelVisitor(ModelSource model)
    {
        modelSource = model;
        BindingMyText = "Test!";
    }
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    override internal string bindingMyText(ModelA source)
    {
        return source.MyTextA;
    }
    override internal void bindingMyText(ModelA source, string val)
    {
        source.MyTextA = val;
    }
    override internal string bindingMyText(ModelB source)
    {
        return source.MyTextB;
    }
    override internal void bindingMyText(ModelB source, string val)
    {
        source.MyTextB = val;
    }
    private ModelSource modelSource;
    public ModelSource ModelSource
    {
        get { return modelSource; }
        set
        {
            modelSource = value;
            OnPropertyChanged("ModelSource");
            OnPropertyChanged("BindingMyText");
        }
    }
    public string BindingMyText
    {
        get
        {
            return modelSource.accept(this); 
        }
        set
        {
            modelSource.accept(this, value);
            OnPropertyChanged("BindingMyText");
        }
    }
}

and many different model sources

public abstract class ModelSource : ViewModelBase
{
    abstract internal A accept<A>(IPropVisitor<A> visitor);
    abstract internal void accept<A>(IPropVisitor<A> visitor, A val);
}

class ModelA : ModelSource
{
    private string myTextA;
    public string MyTextA
    {
        get { return myTextA; }
        set {
            myTextA = value;
            OnPropertyChanged("MyTextA");
        }
    }

    internal override A accept<A>(IPropVisitor<A> visitor)
    {
        return visitor.bindingMyText(this);
    }
    internal override void accept<A>(IPropVisitor<A> visitor, A val)
    {
        visitor.bindingMyText(this, val);
    }

}

class ModelB : ModelSource
{
    private string myTextB;
    public string MyTextB
    {
        get { return myTextB; }
        set
        {
            myTextB = value;
            OnPropertyChanged("MyTextB");
        }
    }
    internal override A accept<A>(IPropVisitor<A> visitor)
    {
        return visitor.bindingMyText(this);
    }

    internal override void accept<A>(IPropVisitor<A> visitor, A val)
    {
        visitor.bindingMyText(this, val);
    }
}

Please note that this is simply the basic idea, so it is really an initial draft and it is not intended to automatically fit any specific context...

  • Why visitor? So many concrete classes, methods, interfaces.. that suppose to be a binding job, just give it a path, done. I am not following why this is necessary and yet you have to set `ModelSource` first somehow (xaml binding lacks source, how do you set it?). Sorry, but it looks like an over-engineering to me... – Sinatr Feb 06 '17 at 12:38
  • @Sinatr absolutely, it is **not** necessary, you can replace it with a more simple switch. And you can set the ModelSource via constructor, let me edit this part –  Feb 06 '17 at 12:44
  • edited, so now I can inject the model source via c.tor –  Feb 06 '17 at 12:48
  • Thanks for all effort, but I don't think it improves anything :( More likely problem in me, I have perk to ask questions which no one understand. – Sinatr Feb 06 '17 at 13:16
  • just out of my curiosity: forget the visitor (that is almost off topic, just for the sake of functional programming...) and the switch... my question is: was it easy and correct the part with those couple of lines to make the property two-way?? I've only posted the answer for your comment "I'd like to see how you'll do it " :-) (btw I didn't expect this actually solved your issue, since I could not fully understand it, my bad!) –  Feb 06 '17 at 13:30