WPF: Databound default with custom override?



  • This seems like an uncommon, if not rare usecase, but I would love to know if people can help:

    I have a data column which needs to be populated, I have another column which is often but not always linked to that one, i.e. if column A = 12, column B = 112 unless the user changes B.

    I am using WPF with a prism/MVVM set up. The behaviour I want is basically:

    1. Automatically set data item B and update it whenever A changes.
    2. If the user manually edits data item B to a different value, stop updating it from A.

    Now for the purposes of making this slightly easier to help with - the rule can be considered as simple as y = x + 100. I thought about setting up a rule like if "y = x + 100 then update", but I'm not sure from a usability point of view which way is best, if they edit the box should I permanently disable the connection? or should I restore it if they put it back? or should I have additional controls (like a "default" checkbox which controls the link?)


  • Discourse touched me in a no-no place

    Is the underlying data is held in a database? Then something like:

    mysql> describe base;
    +-------+---------+------+-----+---------+----------------+
    | Field | Type    | Null | Key | Default | Extra          |
    +-------+---------+------+-----+---------+----------------+
    | id    | int(11) | NO   | PRI | NULL    | auto_increment |
    | a     | int(11) | YES  |     | NULL    |                |
    | b     | int(11) | YES  |     | NULL    |                |
    +-------+---------+------+-----+---------+----------------+
    3 rows in set (0.01 sec)
    
    mysql> select * from base;
    +----+------+------+
    | id | a    | b    |
    +----+------+------+
    |  1 |   12 | NULL |
    |  2 |   14 |   54 |
    |  3 |   64 |   43 |
    |  4 |   56 | NULL |
    +----+------+------+
    4 rows in set (0.00 sec)
    
    mysql> create view derived as select id, a, case when isnull(b) then a+100 else b end as b from base;
    Query OK, 0 rows affected (0.13 sec)
    
    mysql> select * from derived;
    +----+------+------+
    | id | a    | b    |
    +----+------+------+
    |  1 |   12 |  112 |
    |  2 |   14 |   54 |
    |  3 |   64 |   43 |
    |  4 |   56 |  156 |
    +----+------+------+
    4 rows in set (0.03 sec)
    mysql>
    

    Trouble being, of course, that you can't write to derived to update b - you need to write to base



  • It's in a database but this is on a CRUD user control just handling an insert - not an update or anything else, so I am looking for a databinding/MVVM type result



  • This is something I'd handle in the viewmodel. (It's a good case for having one).

    For example

    class
    {
        object a;
        public object A { 
            get { return a; } 
            set { 
                a = value;
                NotifyPropertyUpdated("a");
                b = a + 100;
                NotifyPropertyUpdated("b");
            }
        }
        object b;
        public object B { 
            get { return b; } 
            set { 
                b = value;
                NotifyPropertyUpdated("b");
            }
        }
    
    }
    

    if you want a locking mechanism

    class
    {
        bool locked;
        object a;
        public object A { 
            get { return a; } 
            set { 
                a = value;
                NotifyPropertyUpdated("a");
                if (locked)
                {
                    b = a + 100;
                    NotifyPropertyUpdated("b");
                }
            }
        }
        object b;
        public object B { 
            get { return b; } 
            set { 
                b = value;
                NotifyPropertyUpdated("b");
                locked = false;
                if (value == a + 100) locked = true;
            }
        }
    
    }
    

    Of course, that's very simple, and may have a 'bug' in it depending on how it's used. For example, if order matters in setting a and b values, then the locking can get into a limbo state, or have undefined behavior. At which point you may want to add a checkbox to the grid and make the user choose instead of having it be implicit. This is my preference.

    class
    {
        bool locked;
        public bool Locked { get { return locked; } set { locked = value; Notifyp...
        object a;
        public object A { 
            get { return a; } 
            set { 
                a = value;
                NotifyPropertyUpdated("a");
                if (locked)
                {
                    b = a + 100; // to handle actually setting it in the source database.
                    NotifyPropertyUpdated("b");
                }
            }
        }
        object b;
        public object B { 
            get { if (locked) return a + 100; return b; } 
            set { 
                if (!locked)
                {
                     b = value;
                     NotifyPropertyUpdated("b");
                }
            }
        }
    
    }
    

    So, imo, make it explicit, add a checkbox.

    I absolutely hate editable implicitly updated values in the UI. It's a bad idea.

    Not only is it harder to debug, harder to keep logic consistent and not buggy, but also harder for the user to anticipate what's going on and remember to verify cascading edits when they are done.

    Adding the checkbox makes it easier to control the default state. You want the default to be the most common use case. If the user decides to swap the default, you don't want to have to reverse your implicit logic.

    Well, if I go any further, I'm just going to end up whitepapering a bunch of UI design concepts.



  • @PJH said:

    Is the underlying data is held in a database? Then something like

    Unfortunately, if you don't handle it in the front-end, you'll have to re-load the data every time b changes. If you want the UI to truly be dumb, you'll have round-trip to the database every time you change any field.


  • Discourse touched me in a no-no place

    @xaade said:

    I absolutely hate editable implicitly updated values in the UI. It's a bad idea.

    Not only is it harder to debug, harder to keep logic consistent and not buggy, but also harder for the user to anticipate what's going on and remember to verify cascading edits when they are done.

    If you're going to do it, though, you can slightly improve the experience by changing the color and/or font or background color so the user can distinguish between something he entered and something that's autogenerated.



  • This was exactly what I was looking for. The more I thought about it the more it seemed like a checkbox would be the way to go.

    Much appreciated



  • Having done that (Total set from Hours*Rate, unless you edit Total) in a program I used myself, yeah, ‘usability nightmare’ is putting it mildly.

    @algorythmics said:

    seemed like a checkbox would be the way to go.

    You made the right choice.


Log in to reply