2

In ViewModels there are typically lots of these

private string someField;
public string SomeField
{
    get 
    {
        return someField;   
    }
    set
    {
        someField = value;
        NotifyOfPropertyChanged(() => SomeField);
    }
}

Is there any way to get a short version of such a construct, that is even Bindable?

So that you only have to write something like:

public Bindable<string> SomeField;

perhaps with an action that shall be fired for NotifyPropertyChanged...

Mare Infinitus
  • 8,024
  • 8
  • 64
  • 113

2 Answers2

3

I suppose you could create your own class that maintains a value and raises INotifyPropertyChanged against the containing class that you could create like:

public Bindable<string> SomeField = new Bindable<string>("test", this);

And then Binding against SomeField would access the contained value and setting it would lead to INotifyPropertyChanged being raised against this

You'd need to use some implicit cast operators in order to get the binding system to see your Bindable<T> as a source of T and a place to put T

See: http://msdn.microsoft.com/en-us/library/85w54y0a.aspx

Something along the lines of the following may suffice:

public class Bindable<T>
{
    private T _value;
    private PropertyChangedEventHandler _notifyHandler;
    private INotifyPropertyChanged _notifyTarget;
    private string _name;

    public Bindable(PropertyChangedEventHandler notifyHandler, INotifyPropertyChanged notifyTarget, string name, T value = default(T), bool trigger = false)
    {
        _value = value;
        _name = name;
        _notifyHandler = notifyHandler;
        _notifyTarget = notifyTarget;

        if (trigger)
        {
            _notifyHandler(_notifyTarget, new PropertyChangedEventArgs(_name));
        }
    }

    public implicit operator T(Bindable<T> bindable)
    {
        return bindable._value;
    }

    public implicit operator Bindable<T>(T value)
    {
        return new Bindable<T>(_notifyHandler, _notifyTarget, _name, value, true);
    }
}

The above code is crude and a better version could no doubt be created, but it should point you in the direction you need to go.


On further investigation of my proposed solution I've found that it would be problematic to get to work owing to the implicit cast from T to Bindable<T> in order to remember the target and other details, I'm sure this sort of solution contains enough ideas to lead to a working one.

Clint
  • 6,133
  • 2
  • 27
  • 48
  • I think that the Binding system should even see the `T` only... or there will be some problems when binding e.g. strings to TextBox.Text or that like – Mare Infinitus Apr 05 '13 at 12:27
  • Clint, that's a cool idea, but have you tested that it actually works with databinding? I have my doubts. But there is an easy workaround: Add a property `Value` that encapsulates `_value` and is just a simple implementation notifying property. Binding would have to use this property then. However, this might be problematic in combination with Caliburn.Micro. – Daniel Hilgarth Apr 05 '13 at 12:44
  • @DanielHilgarth I've not directly tested this code no, I've done something similar before though because I'm lazy and `INotifyPropertyChanged` can be a real pain to implement time and time again, the principle is sound even if the code isn't entirely :P But agreed, some frameworks that do freaky reflection things themselves might have issues. – Clint Apr 05 '13 at 12:46
  • @Clint: But even without CM, this is a bit problematic. Assume binding a `Bindable` to a `TextBlock.Text`. I think it will not use the conversion operator, because `Text` is a `string`, not an `int`. The text inside the text block will be the string returned by `Bindable.ToString()`. – Daniel Hilgarth Apr 05 '13 at 12:50
  • This looks very very good. – Mare Infinitus Apr 05 '13 at 12:53
  • @DanielHilgarth You may in fact be correct on that point and that may cause problems for some use cases, but I'd argue that you oughtn't be binding an int to a text property without some interim conversion of your own `IValueConverter` for example because there might be hidden exceptions that get swallowed for incorrect input for example. – Clint Apr 05 '13 at 12:54
  • @MareInfinitus thank you, but be aware, as Daniel pointed out, there could be potential issues surrounding using this level of misdirection to achieve an end-goal, it's not "proper" but it should perform the trick you want. – Clint Apr 05 '13 at 12:55
  • 1
    @Clint: Yes, that's a point I do agree with. I just think it is important to point out the possible problems one can encounter with this solution, so they can be avoided. As I said, I think this is a cool solution. – Daniel Hilgarth Apr 05 '13 at 12:55
0

There exist auto properties, that can be used as a shortcut for properties without logic.

The two following properties are equivalent:

private string someField;
public string SomeField
{
    get { return someField; }
    set { someField = value; }
}

public string SomeField { get; set; }

However, there is no built-in way to introduce a change notification into this.

But if you want to invest time and/or money, there are ways to make auto properties notify about changes:

  1. Use an AOP framework like PostSharp. It will inject this functionality in a post-compile step: http://www.postsharp.net/model/inotifypropertychanged. The disadvantage of this approach is that PostSharp isn't free.
  2. Use dynamically created proxy classes. At runtime, you can create a class that derives from your actual ViewModel and overrides each property with change notification. The disadvantage of this approach is that you would need to use that proxy instead of your class and that all your properties would need to be virtual.
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • Autoproperty is no answer to my question... – Mare Infinitus Apr 05 '13 at 12:26
  • @MareInfinitus: Why do you say that? An auto property alone really isn't the solution, but that's not the core of my answer. – Daniel Hilgarth Apr 05 '13 at 12:26
  • because, in fact, autoproperties have nothing to do the the core of my question. – Mare Infinitus Apr 05 '13 at 12:30
  • 1
    @MareInfinitus: You might want to actually read my answer. The core of your question is: How to make short properties that the UI can bind to? My answer answers this. – Daniel Hilgarth Apr 05 '13 at 12:32
  • You say it could be achieved somehow, but not how. I don't know postsharp, but will try it out. thank you – Mare Infinitus Apr 05 '13 at 12:57
  • 1
    @MareInfinitus: This is not correct. I not only say how it can be achieved, I even give you two different ways of achieving it: (1) using PostSharp (2) using dynamic proxies. – Daniel Hilgarth Apr 05 '13 at 13:00
  • okay, then please point me to where you explain how dynamic proxies solve the problem the question is about. your link to postsharp is only a workaround, it will make all my autoproperties to bindable properties, but that was not the question... – Mare Infinitus Apr 05 '13 at 13:02
  • @MareInfinitus: So, what *was* your question? And how dynamic proxies solve the problem is explained in the last paragraph of my answer. I am tired of you not reading what I write. – Daniel Hilgarth Apr 05 '13 at 13:03
  • Please excuse me. I did not want to annoy you. It's just that "dynamically created proxies" is perhaps not a such common term for me, as it seems to be for you. Can you please elaborate on that? – Mare Infinitus Apr 05 '13 at 19:36