4

I have EntitiesUserControl responsible for EntitiesCount dependency property:

public static readonly DependencyProperty EntitiesCountProperty = DependencyProperty.Register(
    nameof(EntitiesCount),
    typeof(int),
    typeof(EntitiesUserControl),
    new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

public int EntitiesCount
{
    get { return (int)this.GetValue(EntitiesCountProperty); }
    set { this.SetValue(EntitiesCountProperty, value); }
}

Another (primary) control include EntitiesUserControl and read it property through binding:

<controls:EntitiesUserControl EntitiesCount="{Binding CountOfEntities, Mode=OneWayToSource}" />

CountOfEntities property in view model just store and process changing of count value:

private int countOfEntities;
public int CountOfEntities
{
    protected get { return this.countOfEntities; }
    set
    {
        this.countOfEntities = value;
        // Custom logic with new value...
    }
}

I need EntitiesCount property of EntitiesUserControl to be read-only (primary control must not change it, just read) and it works this way only because Mode=OneWayToSource declared explicitly. But if declare TwoWay mode or don't explicitly declare mode, then EntitiesCount could be rewritten from outside (at least right after binding initialization, because it happens after default dependency property value assigned).

I can't do 'legal' read-only dependency property due to binding limitations (best described in this answer), so I need to prevent bindings with mode other than OneWayToSource. It would be best to have some OnlyOneWayToSource flag like BindsTwoWayByDefault value in FrameworkPropertyMetadataOptions enumeration...

Any suggestions how to achieve this?

Community
  • 1
  • 1
Sam
  • 1,384
  • 2
  • 20
  • 30
  • I'm not sure I get what's wrong with using `Mode=OneWayToSource`. The only problem is that you have to type that out or what? Sorry I don't quite grok the problem here. I'll share a hacky way to achieve only `OneWayToSource` binding, but not sure that that's what you need. – Szabolcs Dézsi Feb 25 '16 at 19:12
  • 2
    @SzabolcsDézsi The problem is not that I *have to* type, the problem is just the other way - that I *may not* type, and nothing will tell me that I going to use property the way that it not supposed to be used. As an analogy - you can't compile program if you write code that assign value to read-only property. – Sam Feb 26 '16 at 07:48
  • @Sam FWIW I agree with you and would love to see an elegant solution to this also. But nothing about XAML or WPF seems to espouse the safety philosophy you are referring to :( – StayOnTarget Jul 08 '20 at 18:18

1 Answers1

3

It's a „bit” hacky, but you can create a Binding-derived class and use that instead of Binding:

[MarkupExtensionReturnType(typeof(OneWayToSourceBinding))]
public class OneWayToSourceBinding : Binding
{
    public OneWayToSourceBinding()
    {
        Mode = BindingMode.OneWayToSource;
    }

    public OneWayToSourceBinding(string path) : base(path)
    {
        Mode = BindingMode.OneWayToSource;
    }

    public new BindingMode Mode
    {
        get { return BindingMode.OneWayToSource; }
        set
        {
            if (value == BindingMode.OneWayToSource)
            {
                base.Mode = value;
            }
        }
    }
}

In XAML:

<controls:EntitiesUserControl EntitiesCount="{local:OneWayToSourceBinding CountOfEntities}" />

The namespace mapping local might be something else for you.

This OneWayToSourceBinding sets the Mode to OneWayToSource and prevents setting it to anything else.

Szabolcs Dézsi
  • 8,743
  • 21
  • 29
  • Thanks for example, it is enough interesting, at least I have newer used bindings this way... That is not exactly what I need, but it somewhat relative: just like your custom binding prevent using any mode other than 'OneWayToSource', I need dependency property to prevent binding to itself any binding other than your custom binding, or any standart binding with mode other than 'OneWayToSource'. – Sam Feb 25 '16 at 21:50