Skip navigation
Currently Being Moderated

Checkbox visual out of sync with property value.  Work-around?

May 2, 2012 3:20 PM

I'd like to be able to override a checkbox with code similar to this:

 

f:checkbox {

    title = "Some Title",

    value = bind { key = 'someProperty',

        transform = function(value, fromModel)

            if not fromModel then

                if not userReallyWantsToDoThis() then

                    value = not value

                end

            end

           

            return value

        end,

    },

    checked_value = true,

    unchecked_value = false,

}

 

This works so far as setting the bound property goes, but the visual representation doesn't change if the transform is perfomed (e.g. if the incoming and outgoing "transform" values differ).  So, even if the user changed his mind, it still looks like the override didn't happen (i.e. the box is still checked/unchecked as the case may be).

 

Has anyone else seen this behavior?  Any work-arounds?  BTW, this is on LR 3.6 -- I haven't tried any others.

 

-Don

 
Replies
  • Currently Being Moderated
    May 2, 2012 5:19 PM   in reply to Don McKee

    Remove the clause that confines the behavior to "not fromModel", i.e.

     

          transform = function(value, fromModel)

                if not userReallyWantsToDoThis() then

                    value = not value

                end

               

                return value

            end

     

     

    Should work.

     
    |
    Mark as:
  • Currently Being Moderated
    May 2, 2012 6:36 PM   in reply to Don McKee

    I'm not sure what to say - I've never had this trouble.

     

    But make sure you check for errors in userReallyWantsToDoThis(). e.g. pcall or function-context handler.

     
    |
    Mark as:
  • Currently Being Moderated
    May 2, 2012 8:30 PM   in reply to Don McKee

    I couldn't get your approach to work either.  But I was able to use a property-table observer to make it work:

     

     

    local Require = require 'Require'.path ("../common")
    local Debug = require 'Debug'
    require 'strict'
    
    local LrBinding = import 'LrBinding' 
    local LrDialogs = import 'LrDialogs' 
    local LrFunctionContext = import 'LrFunctionContext' 
    local LrRecursionGuard = import 'LrRecursionGuard'
    local LrView = import 'LrView' 
    
    local bind = LrView.bind 
    local f = LrView.osFactory()
    local recursionGuard = LrRecursionGuard ("check")
    
    local function userReallyWantsToDoThis (prop, key, newValue)
        recursionGuard:performWithGuard (function ()
            if "ok" == LrDialogs.confirm ("Do you want to do this?") then
                prop.check = newValue
            else
                prop.check = not prop.check
                end
            end)
        end
    
    LrFunctionContext.callWithContext ("", function (context) 
        local prop = LrBinding.makePropertyTable (context) 
        prop.check = false
        prop:addObserver ("check", userReallyWantsToDoThis)
        LrDialogs.presentModalDialog {title = "Test",  
            contents = f:column {bind_to_object = prop, 
                f:checkbox {title = "Some Title",
                    checked_value = true, unchecked_value = false,
                    value = bind {key = "check"}}}}
        end)
    
    
     
    |
    Mark as:
  • Currently Being Moderated
    May 21, 2012 6:09 AM   in reply to Don McKee

    [[Apologies if anyone has seen this response previously. Responded by email and it appears that never made it through to the forums.]]

     

    Hi Don,

     

    I was trying to work out the logic behind this. Let me know whether you agree with the reasoning here.

     

    The value is being bound to propertyTable.someProperty. Every time this property's value changes it then executes all observers including the transform function to convert the value into the value needed by the checkbox.

     

    In your original transform function it was synchronously resetting that exact same bound value to a different value. There are only two ways I think that situation can be handled:

    1) when you set the property value from within the transform function, recursively call all observers (and thus the transform function) again before setting the value

    2) suspend all observers for the property value during the transform function to avoid getting into a recursive loop

    Looks like the team have gone with option 2) here.

     

    So to me this behaviour makes sense as otherwise it would be difficult to impossible to commit the property table processing with a consistent state.

     

    If above holds true it is possible that you don't even need the sleep() call in your async task. Setting the property value from within the async task might be enough to allow the original property table observer to commit the value in a consistent state. If the sleep() proves necessary then people who make extensive use of async tasks will need to be very careful when setting property table entries, lest they encounter intermittent issues where observers don't fire because of this very situation.

     

    Did that make sense?

     

    Matt

     
    |
    Mark as:

More Like This

  • Retrieving data ...

Bookmarked By (0)

Answers + Points = Status

  • 10 points awarded for Correct Answers
  • 5 points awarded for Helpful Answers
  • 10,000+ points
  • 1,001-10,000 points
  • 501-1,000 points
  • 5-500 points