OpenLightGroup Blog

rss

Blogs from OpenLightGroup.net


PollResultsBarBehavior – Binding to Multiple Values Through a Behavior and Custom Dependency Properties

This is a follow up to my previous article PollResultsBar – Binding to Multiple Values Through Inheritance and Custom Dependency Properties

image

In it I describe how to bind a single ProgressBar property to multiple ViewModel properties through use of an inherited class so I can bind the Maximum property to the sum of the Agree and Disagree counts. I found it’s possible to accomplish the same thing through a behavior:

DownloadCode:

http://richardwaddell.adefwebserver.com/PollResultsBarBehaviorDemo.zip

The Behavior

namespace PollResultsBarDemo
{
    public class PollResultsBarBehavior : Behavior<DependencyObject>
    {
        ProgressBar _progressBar;
        public PollResultsBarBehavior()
        {
	}
        protected override void OnAttached()
        {
	    base.OnAttached();
            _progressBar = AssociatedObject as ProgressBar;
	}
        protected override void OnDetaching()
        {
	    base.OnDetaching();
	}
        public static readonly DependencyProperty LeftValueProperty =
             DependencyProperty.Register("LeftValue",
                                             typeof(int),
                                             typeof(PollResultsBarBehavior),
                                             new PropertyMetadata(50, new PropertyChangedCallback(OnLeftValueChanged)));
        public static readonly DependencyProperty RightValueProperty =
             DependencyProperty.Register("RightValue",
                                             typeof(int),
                                             typeof(PollResultsBarBehavior),
                                             new PropertyMetadata(50, new PropertyChangedCallback(OnRightValueChanged)));
        public int LeftValue
        {
            get { return (int)base.GetValue(LeftValueProperty); }
            set { base.SetValue(LeftValueProperty, value); }
        }
        public int RightValue
        {
            get { return (int)base.GetValue(RightValueProperty); }
            set { base.SetValue(RightValueProperty, value); }
        }
        public static void OnLeftValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            SetMaximum(d as PollResultsBarBehavior);
            SetValue(d as PollResultsBarBehavior, (int)e.NewValue);
        }
        public static void SetValue(PollResultsBarBehavior bar, int value)
        {
            if (DesignerProperties.GetIsInDesignMode(Application.Current.RootVisual))
                return;
            if (bar._progressBar != null)
                bar._progressBar.Value = value;
        }
        public static void OnRightValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            SetMaximum(d as PollResultsBarBehavior);
        }
        private static void SetMaximum(PollResultsBarBehavior bar)
        {
            if (DesignerProperties.GetIsInDesignMode(Application.Current.RootVisual))
                return;
            if (bar._progressBar != null)
                bar._progressBar.Maximum = bar.LeftValue + bar.RightValue;
        }
    }

The code is not that different, we are just applying the Behavior properties to the attached ProgressBar instead of applying new  properties in the inherited class to base properties of the ProgressBar class we inherited from. You could say that the behavior has a ProgressBar, whereas PollResultsBar is a ProgressBar.

Find the behavior under Assets/Behaviors and attach to the ProgressBar you used to replace PollResultsBar. Notice that nothing triggers the behavior. It simply detects changes to its properties and applies them to the ProgressBar:

image

Now bind the behavior LeftValue and RightValue properties by dragging from MainPageViewModel:

image

and selecting from the dropdown:

image

Do the same with DisagreeCount and the RightValue Property.

You may notice above that Blend is unhappy with these settings. At some point it may show an exception in the design area and prevent you from getting out of the ItemTemplate and back to MainPage.xaml. In this case close Blend and reopen and everything should be fine. There seemed to be fewer problems if you bind AgreeCount and Disagree count by binding the long way:

image

and then picking AgreeCount:

image

Well, maybe not. Just tried it again and Blend threw an exception

image

At this point you can’t get out of the ItemTemplate so you have to re-start Blend.

Fortunately, I found a way to avoid the problem. If I find myself in Design Mode when I’m about to set a ProgressBar property I bail :

        public static void SetValue(PollResultsBarBehavior bar, int value)
        {
            if (DesignerProperties.GetIsInDesignMode(Application.Current.RootVisual))
                return;
            if (bar._progressBar != null)
                bar._progressBar.Value = value;
        }
        private static void SetMaximum(PollResultsBarBehavior bar)
        {
            if (DesignerProperties.GetIsInDesignMode(Application.Current.RootVisual))
                return;
            if (bar._progressBar != null)
                bar._progressBar.Maximum = bar.LeftValue + bar.RightValue;
        }

When you run the app you should see:

image

Summary

It’s hard to say which it the better approach. It probably comes down to which provides the more reusable code, which probably depends on the circumstance.

I am fascinated by behaviors and the concept of a control that provides the capabilities but is exclusively directed by behaviors in its actual activities, so I’ll probably lean in the direction of using them.





Comments are closed.