WPF PropertyStatus and Tabs

WPF PropertyStatus and Tabs

Old forum URL: forums.lhotka.net/forums/t/9590.aspx


Curelom posted on Wednesday, September 29, 2010

I'm using the Telerik Tab Control.  I have controls on one tab which cause business rule validations to controls on a different tab, i.e. if a certain value in a dropdown is selected then a field on another tab is required.

Apparently the Telerik Tab Control doesn't initialize it's tabs until they are brought into view, so when I invalidate a field, then click on that tab, I only see the textbox with a red error border around it and DON'T see a visible propertystatus with it's error icon and popup.  Once I have been to the tab and go back to the drop down on the other tab, select a value to clear the broken rule, then select a value to break a rule again, I can select the other tab and I CAN see the propertystatus this time.  What is the best way to get the propertystatus to reevaluate itself visually?  I can see a protected GoToState method in the PropertyStatus code, but it has some checks in it so that if the state hadn't changed from the previous state, it won't reevaluate.  I've tried subclassing the PropertyStatus, but there are a number of private members that make this difficult.

RockfordLhotka replied on Thursday, September 30, 2010

The primary trigger PropertyStatus uses to know it should refresh is a PropertyChanged event from the data source object. It will also refresh if the DataContext is changed.

Curelom replied on Thursday, September 30, 2010

Yes it does, but it doesn't refresh if the status hasn't changed.  If the status is already error, which it is, and I call a propertychanged, it checks if the status is the same, which it is, and doesn't refresh.

Code from the GoToState method

      if (newState != _lastState)
      {
        _lastState = newState;
        DisablePopup(_lastImage);
        VisualStateManager.GoToState(this, newState, useTransitions);
        if (newState != "Busy" && newState != "PropertyValid")
        {
          _lastImage = (FrameworkElement)FindChild(this, string.Format("{0}Image", newState.ToLower()));
          EnablePopup(_lastImage);
        }
      }

RockfordLhotka replied on Thursday, September 30, 2010

Are you using 4.0.1? We changed some of this behavior from 4.0 to 4.0.1 so there are more conditions under which it will refresh.

Curelom replied on Thursday, September 30, 2010

I'm using 4.0.1

Russ replied on Thursday, September 30, 2010

So am I.

RockfordLhotka replied on Thursday, September 30, 2010

Fair enough. Let me put this another way then. What would you like to see?

I assume you'd like the control to just automatically work in this scenario, though I'm not entirely sure that's possible given the loading/rendering order of events.

Is there some (possibly optional) event the control could be listening for to do a forced refresh?

Curelom replied on Thursday, September 30, 2010

Ideally, if I could have the propertystatus forced refresh fire on a tab selection event, perhaps using a TriggerEvent, though the project I'm working on hasn't been upgraded to MVVM yet, or I could handle each propertystatus individually in a tab selection event.  So I believe what I would like is a public method which forces a state update.

RockfordLhotka replied on Thursday, September 30, 2010

If there was a "public void Redraw()" method, it would support code-behind and TriggerAction since both can invoke methods with no parameters.

Do you want to prototype this idea and see if it meets your needs?

Curelom replied on Thursday, September 30, 2010

Yes, I'll try to get to it this afternoon.

Curelom replied on Thursday, September 30, 2010

I think I've come up with a better solution.  I've tested it, and it does work in my scenario.

I've added and modified the following code to PropertyStatus.  It can then be invoked by xaml <csla:PropertyStatus IsForceRedraw="True" ...

protected bool _isForceRedraw = false;
        /// <summary>
        /// Gets a value indicating whether PropertyStatus
        /// will redraw even if the state remains the same
        /// </summary>
        [Category("Property Status")]
        public bool IsForceRedraw {
            get {
                return _isForceRedraw;
            }
            set {
                _isForceRedraw = value;
            }
        }
        /// <summary>
        /// Updates the status of the Property in UI
        /// </summary>
        /// <param name="useTransitions">if set to <c>true</c> then use transitions.</param>
        protected virtual void GoToState(bool useTransitions) {
            if (_loading) return;

            BusyAnimation busy = FindChild(this"busy"as BusyAnimation;
            if (busy != null)
                busy.IsRunning = IsBusy;

            string newState;
            if (IsBusy)
                newState = "Busy";
            else if (IsValid)
                newState = "PropertyValid";
            else
                newState = RuleSeverity.ToString();

            if (_isForceRedraw || newState != _lastState) {
                _lastState = newState;
                DisablePopup(_lastImage);
                VisualStateManager.GoToState(this, newState, useTransitions);
                if (newState != "Busy" && newState != "PropertyValid") {
                    _lastImage = (FrameworkElement)FindChild(thisstring.Format("{0}Image", newState.ToLower()));
                    EnablePopup(_lastImage);
                }
            }
        }

Curelom replied on Friday, October 08, 2010

Alas(who uses Alas), my above change doesn't work entirely.  My window has a gridview and a detail control where the propertystatus controls are.  Using this solution, I can see the propertystatus in error correctly, however, if I click on a different row in the grid, which changes the datacontext of the detail control, the propertystatus in the detail control still shows as error.  I have also verified that the source it is still pointing to is still the old row.  Here's the kicker, if I go and type something into the textbox in error and navigatge rows, the propertystatus finds itself again and shows properly for each row.  I'm completely baffled by this behavior.  Any ideas on what is going on? 

Curelom replied on Monday, October 11, 2010

I've narrowed down this latest issue I am having.  It doesn't have anything to do with tabs or the changes I have made.  I built a test app to duplicate the problem to put it out here, but the test app works perfectly. Sad  Anyway, enough of my rambling.

Russ replied on Thursday, September 30, 2010

I have observed the same behaviour using the Microsoft Tab control in VS2010.

Copyright (c) Marimer LLC