{"id":59,"date":"2013-01-29T17:38:00","date_gmt":"2013-01-29T17:38:00","guid":{"rendered":"http:\/\/www.mishmashmakers.com\/michelle\/?p=59"},"modified":"2017-02-08T14:49:54","modified_gmt":"2017-02-08T19:49:54","slug":"three-thumb-slider-example","status":"publish","type":"post","link":"https:\/\/www.mishmashmakers.com\/michelle\/2013\/01\/three-thumb-slider-example\/","title":{"rendered":"Three Thumb Slider Example"},"content":{"rendered":"<body><p><\/p>A few days ago I was looking for a WPF slider that had three thumbs for a project I was working on. The three thumbs needed to be able to be customized individually and the central\u00a0thumb\u00a0needed to never exceed the values or locations of the left or right thumbs (i.e., think a video timeline with starting and ending points you can modify with the center thumb never exceeding these points). After searching for quite a while, all I could find was a slider with two thumbs so I modified it and decided to put it the modifications here to help out others who may need the same thing.\n<p><img data-recalc-dims=\"1\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/i0.wp.com\/4.bp.blogspot.com\/-eS6QvH88QU8\/UQf-Mcin0kI\/AAAAAAAAA0Q\/cQkVNVjldUc\/s320\/Capture.PNG?resize=320%2C158\" width=\"320\" height=\"158\" loading=\"lazy\"><br>\nTo break the code down a little bit there are three main sections, the actual slider component, the event handling of the three thumbs, and the invocation of the slider.<\/p>\n<h3 style=\"text-align: left;\">Slider Component<\/h3>\n<p>In the User Control xaml (ThreeThumbSlider.xaml), I added an\u00a0additional\u00a0slider thumb using the below code. This allows for the three thumbs to be rendered on the slider.<\/p>\n<p>&lt;Slider x:Name=\u201dMiddleSlider\u201d Minimum=\u201d{Binding ElementName=root, Path=Minimum}\u201d Maximum=\u201d{Binding ElementName=root, Path=Maximum}\u201d Value=\u201d{Binding ElementName=root, Path=MiddleValue, Mode=TwoWay}\u201d Template=\u201d{StaticResource simpleSlider}\u201d Margin=\u201d0,0,0,0\u2033\/&gt;<\/p>\n<p>In addition, data binding and a dynamic resource allows for the color\u00a0of\u00a0each thumb to be modified. In the\u00a0UserControl.Resources Track ControlTemplate I added the following:<\/p>\n<p>&lt;Rectangle Fill=\u201d{<strong>DynamicResource ResourceKey=Clr<\/strong>}\u201d Stroke=\u201dBlack\u201d StrokeThickness=\u201d1\u2033 Width=\u201d10\u2033 Height=\u201d18\u2033 SnapsToDevicePixels=\u201dTrue\u201d\/&gt;<\/p>\n<p>The following Resource Key was added within each of the thumbs:<br>\n&lt;Slider x:Name=\u201dMiddleSlider\u201d Minimum=\u201d{Binding ElementName=root, Path=Minimum}\u201d Maximum=\u201d{Binding ElementName=root, Path=Maximum}\u201d Value=\u201d{Binding ElementName=root, Path=MiddleValue, Mode=TwoWay}\u201d Template=\u201d{StaticResource simpleSlider}\u201d \u00a0Margin=\u201d0,0,0,0\u2033&gt;<br>\n<strong>\u00a0 \u00a0 \u00a0 &lt;Slider.Resources&gt;<\/strong><br>\n<strong>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 &lt;Brush x:Key=\u201dClr\u201d&gt;Green&lt;\/Brush&gt;<\/strong><br>\n<strong>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 &lt;\/Slider.Resources&gt;<\/strong><br>\n&lt;\/Slider&gt;<\/p>\n<h3 style=\"text-align: left;\">Event Handling of the Three Thumbs<\/h3>\n<p>The event handling of the three thumbs is a bit tricky because you need to make sure that the middle slider does not exceed the values or location of the upper and lower valued sliders. If it does, the interaction can get a bit confusing. What I ended up doing was making three additional event handlers and checking for instances where the middle value exceeded the upper or lower thumb values using Math.Max() and Math.Min(). When this occurred, I reset the middle thumb value or the upper\/lower values.<\/p>\n<p>public event EventHandler LowerValueChanged;<br>\npublic event EventHandler MiddleValueChanged;<br>\npublic event EventHandler UpperValueChanged;<br>\n\u2026.<br>\nvoid Slider_Loaded(object sender, RoutedEventArgs e)<br>\n{<br>\nLowerSlider.ValueChanged += LowerSlider_ValueChanged;<br>\nUpperSlider.ValueChanged += UpperSlider_ValueChanged;<br>\nMiddleSlider.ValueChanged += MiddleSlider_ValueChanged;<br>\n}<br>\npublic void LowerSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs&lt;double&gt; e)<br>\n{<br>\nMiddleSlider.Value = Math.Max(MiddleSlider.Value, LowerSlider.Value);<br>\nLowerValueChanged(this, e);<br>\n}<br>\npublic void UpperSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs&lt;double&gt; e)<br>\n{<br>\nMiddleSlider.Value = Math.Min(MiddleSlider.Value, UpperSlider.Value);<br>\nUpperValueChanged(this, e);<br>\n}<br>\npublic void MiddleSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs&lt;double&gt; e)<br>\n{<br>\nLowerSlider.Value = Math.Min(MiddleSlider.Value, LowerSlider.Value);<br>\nUpperSlider.Value = Math.Max(UpperSlider.Value, MiddleSlider.Value);<br>\nMiddleValueChanged(this, e);<br>\n}<br>\nTo specify the thumb value for the middle slider, an additional variable and DependancyProperty were also added:<\/p>\n<p>public double MiddleValue<br>\n{<br>\nget { return (double)GetValue(MiddleValueProperty); }<br>\nset { SetValue(MiddleValueProperty, value); }<br>\n}<br>\npublic static readonly DependencyProperty MiddleValueProperty =\u00a0DependencyProperty.Register(\u201cMiddleValue\u201d, typeof(double), typeof(ThreeThumbSlider), new UIPropertyMetadata(0d));<\/p>\n<h3 style=\"text-align: left;\">Invocation of the Slider<\/h3>\n<div style=\"text-align: left;\"><\/div>\n<p>The following line can be added to any .xaml file (in my case the MainWindow.xaml) and allows for the specification of the lower, upper, and middle values of the thumbs as well as the handling of each thumb\u2019s events:<\/p>\n<p>&lt;local:ThreeThumbSlider x:Name=\u201dslider\u201d \u00a0<strong>LowerValue=\u201d30\u2033 UpperValue=\u201d70\u2033 MiddleValue=\u201d40\u2033<\/strong> Minimum=\u201d0\u2033 Maximum=\u201d100\u2033<strong> LowerValueChanged=\u201dvalueChange\u201d UpperValueChanged=\u201dvalueChange\u201d MiddleValueChanged=\u201dvalueChange\u201d<\/strong> Canvas.Left=\u201d81.955\u2033 Canvas.Top=\u201d34.811\u2033 Width=\u201d333.534\u2033\/&gt;<\/p>\n<p>Within the code behind of the MainWindow.xaml.cs, one event handler\u00a0receives\u00a0the changes to the thumbs and modifies the lower, middle, and upper labels using the code below. They are currently tied to a single event handler, but could easily be changed to individual event handlers or other functionality.<\/p>\n<p>public void valueChange(object sender, EventArgs e)<br>\n{<br>\nlowerLabel.Text = slider.LowerValue.ToString();<br>\nupperLabel.Text = slider.UpperValue.ToString();<br>\nmiddleLabel.Text = slider.MiddleValue.ToString();<br>\n}<\/p>\n<\/body>","protected":false},"excerpt":{"rendered":"<p>A few days ago I was looking for a WPF slider that had three thumbs for a project I was working on. The three thumbs needed to be able to be customized individually and the central\u00a0thumb\u00a0needed to never exceed the values or locations of the left or right thumbs (i.e., think a video timeline with [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[48],"tags":[],"class_list":["post-59","post","type-post","status-publish","format-standard","hentry","category-other"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p7fMLx-X","_links":{"self":[{"href":"https:\/\/www.mishmashmakers.com\/michelle\/wp-json\/wp\/v2\/posts\/59","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mishmashmakers.com\/michelle\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mishmashmakers.com\/michelle\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mishmashmakers.com\/michelle\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mishmashmakers.com\/michelle\/wp-json\/wp\/v2\/comments?post=59"}],"version-history":[{"count":5,"href":"https:\/\/www.mishmashmakers.com\/michelle\/wp-json\/wp\/v2\/posts\/59\/revisions"}],"predecessor-version":[{"id":696,"href":"https:\/\/www.mishmashmakers.com\/michelle\/wp-json\/wp\/v2\/posts\/59\/revisions\/696"}],"wp:attachment":[{"href":"https:\/\/www.mishmashmakers.com\/michelle\/wp-json\/wp\/v2\/media?parent=59"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mishmashmakers.com\/michelle\/wp-json\/wp\/v2\/categories?post=59"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mishmashmakers.com\/michelle\/wp-json\/wp\/v2\/tags?post=59"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}