/// <summary> /// Returns the sum total of "low" range scores, given a RangeSlider /// that just had its value modified. /// </summary> /// <param name="sender"></param> /// <param name="newValue"></param> /// <returns>Sum of current "low" values</returns> double GetNewSumOfLowRange(RangeSliderX sender, double newValue) { // Start with the supplied new value double total = newValue; for (int i = 0; i < 5; i++) { if (_sliders[i] != sender) { total += _sliders[i].Low; } } return(total); }
public ScoreDistributionControl() { // Five columns, one for each star category RangeSlider //ColumnDefinition col; for (int i = 0; i < 5; i++) { AddColumn(20, GridUnitType.Star); } // Two rows, one for the header and one for the controls AddRow(10, GridUnitType.Star); AddRow(90, GridUnitType.Star); // Control header TextBlock text = new TextBlock(); text.Background = new SolidColorBrush(Colors.LightGray); ToolTip tip = new ToolTip(); tip.Content = "Specify how the results should be distributed." + Environment.NewLine; tip.Content += "For instance, if you set the one-star 'high' slider to 5%, it means that" + Environment.NewLine; tip.Content += "the returned items will have no more than 5% one-star reviews."; text.ToolTip = tip; text.Foreground = new SolidColorBrush(Colors.Blue); text.Text = "Result percentage ranges per star category"; text.TextAlignment = TextAlignment.Center; AddContent(text, 0, 0, 5); // Five range sliders; one for each star category for (int i = 0; i < 5; i++) { RangeSliderX slider = new RangeSliderX(); slider.HeaderText = (i + 1).ToString() + " - Star"; slider.High = 100; slider.Low = 0; slider.VerticalAlignment = VerticalAlignment.Stretch; slider.HorizontalAlignment = HorizontalAlignment.Stretch; _sliders[i] = slider; //_sliders[i] = new RangeSliderX((i+1).ToString() + " - Star", new DoubleRange(0, 100)) //{ // VerticalAlignment = System.Windows.VerticalAlignment.Stretch, // HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch, //}; _sliders[i].LowValueChanged += slider_LowValueChanged; AddContent(_sliders[i], 1, i, 1); } }
/// <summary> /// Given a RangeSlider, provides a list of the other RangeSliders that have /// a positive "low" range value. Used when adjusting the total of the "low" /// range sliders to not exceed 100%. /// </summary> /// <param name="sender"></param> /// <returns></returns> List <RangeSliderX> GetOtherSlidersWithPositiveLowScore(RangeSliderX sender) { List <RangeSliderX> results = new List <RangeSliderX>(); // Loop through and get the sliders (besides the sender) // that have a positive "low" range value. for (int i = 0; i < 5; i++) { if (_sliders[i] != sender && _sliders[i].Low > 0) { results.Add(_sliders[i]); } } return(results); }
public ScoreDistributionControl() { // Five columns, one for each star category RangeSlider //ColumnDefinition col; for (int i = 0; i < 5; i++) { AddColumn(20, GridUnitType.Star); } // Two rows, one for the header and one for the controls AddRow(10, GridUnitType.Star); AddRow(90, GridUnitType.Star); // Control header TextBlock text = new TextBlock(); text.Background = new SolidColorBrush(Colors.LightGray); ToolTip tip = new ToolTip(); tip.Content = "Specify how the results should be distributed." + Environment.NewLine; tip.Content += "For instance, if you set the one-star 'high' slider to 5%, it means that" + Environment.NewLine; tip.Content += "the returned items will have no more than 5% one-star reviews."; text.ToolTip = tip; text.Foreground = new SolidColorBrush(Colors.Blue); text.Text = "Result percentage ranges per star category"; text.TextAlignment = TextAlignment.Center; AddContent(text, 0, 0, 5); // Five range sliders; one for each star category for (int i = 0; i < 5; i++) { RangeSliderX slider = new RangeSliderX(); slider.HeaderText = (i+1).ToString() + " - Star"; slider.High = 100; slider.Low = 0; slider.VerticalAlignment = VerticalAlignment.Stretch; slider.HorizontalAlignment = HorizontalAlignment.Stretch; _sliders[i] = slider; //_sliders[i] = new RangeSliderX((i+1).ToString() + " - Star", new DoubleRange(0, 100)) //{ // VerticalAlignment = System.Windows.VerticalAlignment.Stretch, // HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch, //}; _sliders[i].LowValueChanged += slider_LowValueChanged; AddContent(_sliders[i], 1, i, 1); } }
/// <summary> /// Prevents user from specifying a total minimum number of results that exceeds 100% /// by dynamically reducing the values of the other sliders. /// </summary> /// e.g. the user specifies 40% for the "low" range value of each of the five /// star categories. The sum would be 200% and wouldn't make sense. /// <param name="sender"></param> /// <param name="oldValue"></param> /// <param name="newValue"></param> void slider_LowValueChanged(RangeSliderX sender, double oldValue, double newValue) { // If we're already dealing with with this problem, allow it to resolve. // This prevents a cascade of events as every change to a low score causes // this method to be called if (resolvingPercentageError) { return; } // Figure out whether the change puts the "low" sum over 100% double sum = GetNewSumOfLowRange(sender, newValue); if (sum <= 100) { return; } resolvingPercentageError = true; // Loop through the sliders, reducing each until // the total amount is less than or equal to 100 while (sum > 100) { // We can't do anything with sliders with a zero "low" value, so get // a list of other sliders that have a non-zero "low" value List<RangeSliderX> hasLowRangeValue = GetOtherSlidersWithPositiveLowScore(sender); foreach (RangeSliderX rangeSlider in hasLowRangeValue) { // how much more we have to distribute double amountAboveOneHundred = sum - 100; // The amount over 100 divided by the number of sliders that have // a "low" value. double shareOfAmountOver = Math.Ceiling(amountAboveOneHundred / hasLowRangeValue.Count); // Try to subtract this amount from the current slider double remainder = rangeSlider.Low - Math.Ceiling(amountAboveOneHundred / hasLowRangeValue.Count); // Two possibilities: // 1) The slider had enough "low" value to subtract its share of the overage if (remainder > 0) { sum -= shareOfAmountOver; rangeSlider.Low = remainder; } else // 2) We could only subtract a part of this slider's share before it became zero { // We've reduced this slider's "low" value to zero rangeSlider.Low = 0; // The negative remainder represents the amount that we couldn't subtract // from this slider. Adjust sum to reflect the portion that we subtracted sum -= (shareOfAmountOver - Math.Abs(remainder)); } } // for each rangeslider with a low value } // sum > 100 // The problem has been successfully resolved. resolvingPercentageError = false; }
/// <summary> /// Given a RangeSlider, provides a list of the other RangeSliders that have /// a positive "low" range value. Used when adjusting the total of the "low" /// range sliders to not exceed 100%. /// </summary> /// <param name="sender"></param> /// <returns></returns> List<RangeSliderX> GetOtherSlidersWithPositiveLowScore(RangeSliderX sender) { List<RangeSliderX> results = new List<RangeSliderX>(); // Loop through and get the sliders (besides the sender) // that have a positive "low" range value. for (int i = 0; i < 5; i++) { if (_sliders[i] != sender && _sliders[i].Low > 0) { results.Add(_sliders[i]); } } return results; }
/// <summary> /// Returns the sum total of "low" range scores, given a RangeSlider /// that just had its value modified. /// </summary> /// <param name="sender"></param> /// <param name="newValue"></param> /// <returns>Sum of current "low" values</returns> double GetNewSumOfLowRange(RangeSliderX sender,double newValue) { // Start with the supplied new value double total = newValue; for (int i = 0; i < 5; i++) { if (_sliders[i] != sender) { total += _sliders[i].Low; } } return total; }
/// <summary> /// Prevents user from specifying a total minimum number of results that exceeds 100% /// by dynamically reducing the values of the other sliders. /// </summary> /// e.g. the user specifies 40% for the "low" range value of each of the five /// star categories. The sum would be 200% and wouldn't make sense. /// <param name="sender"></param> /// <param name="oldValue"></param> /// <param name="newValue"></param> void slider_LowValueChanged(RangeSliderX sender, double oldValue, double newValue) { // If we're already dealing with with this problem, allow it to resolve. // This prevents a cascade of events as every change to a low score causes // this method to be called if (resolvingPercentageError) { return; } // Figure out whether the change puts the "low" sum over 100% double sum = GetNewSumOfLowRange(sender, newValue); if (sum <= 100) { return; } resolvingPercentageError = true; // Loop through the sliders, reducing each until // the total amount is less than or equal to 100 while (sum > 100) { // We can't do anything with sliders with a zero "low" value, so get // a list of other sliders that have a non-zero "low" value List <RangeSliderX> hasLowRangeValue = GetOtherSlidersWithPositiveLowScore(sender); foreach (RangeSliderX rangeSlider in hasLowRangeValue) { // how much more we have to distribute double amountAboveOneHundred = sum - 100; // The amount over 100 divided by the number of sliders that have // a "low" value. double shareOfAmountOver = Math.Ceiling(amountAboveOneHundred / hasLowRangeValue.Count); // Try to subtract this amount from the current slider double remainder = rangeSlider.Low - Math.Ceiling(amountAboveOneHundred / hasLowRangeValue.Count); // Two possibilities: // 1) The slider had enough "low" value to subtract its share of the overage if (remainder > 0) { sum -= shareOfAmountOver; rangeSlider.Low = remainder; } else // 2) We could only subtract a part of this slider's share before it became zero { // We've reduced this slider's "low" value to zero rangeSlider.Low = 0; // The negative remainder represents the amount that we couldn't subtract // from this slider. Adjust sum to reflect the portion that we subtracted sum -= (shareOfAmountOver - Math.Abs(remainder)); } } // for each rangeslider with a low value } // sum > 100 // The problem has been successfully resolved. resolvingPercentageError = false; }