MaterialDesignInXAML/MaterialDesignInXamlToolkit · error · ArgumentOutOfRangeException

MinuteSelectionStep must be a divisor of 60 and between 1 an

Error message

MinuteSelectionStep must be a divisor of 60 and between 1 and 60.

What it means

`Clock.MinuteSelectionStep` is a `DependencyProperty` whose change callback validates the new int: it must be in [1,60] and divide 60 evenly, else `ArgumentOutOfRangeException`. Because the validation lives in the property-changed callback (not a `ValidateValueCallback`), an invalid value set via XAML/binding is assigned first and then the callback throws, which can surface as an unhandled XAML parse or binding exception.

Source

Thrown at src/MaterialDesignThemes.Wpf/Clock.cs:250

        nameof(CornerRadius), typeof(CornerRadius), typeof(Clock), new PropertyMetadata(default(CornerRadius)));

    public CornerRadius CornerRadius
    {
        get => (CornerRadius)GetValue(CornerRadiusProperty);
        set => SetValue(CornerRadiusProperty, value);
    }

    public static readonly DependencyProperty MinuteSelectionStepProperty = DependencyProperty.Register(
        nameof(MinuteSelectionStep), typeof(int),typeof(Clock), new PropertyMetadata(1, MinuteSelectionStepPropertyChangedCallback));

    private static void MinuteSelectionStepPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var clock = (Clock)d;

        int step = (int)e.NewValue;

        if (step < 1 || step > 60 || 60 % step != 0)
            throw new ArgumentOutOfRangeException(
                nameof(MinuteSelectionStep),
                $"{nameof(MinuteSelectionStep)} must be a divisor of 60 and between 1 and 60.");

        clock.GenerateButtons();
    }

    public int MinuteSelectionStep
    {
        get => (int)GetValue(MinuteSelectionStepProperty);
        set => SetValue(MinuteSelectionStepProperty, value);
    }

    public static readonly RoutedEvent ClockChoiceMadeEvent =
        EventManager.RegisterRoutedEvent(
            "ClockChoiceMade",
            RoutingStrategy.Bubble,
            typeof(ClockChoiceMadeEventHandler),
            typeof(Clock));

View on GitHub (pinned to 98edec3a0b)

Solutions

  1. Use a valid divisor of 60 within 1-60: 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, or 60.
  2. Constrain the source of any binding to that same set (an enum or validated combo box).
  3. If allowing arbitrary steps, snap to the nearest valid divisor before assigning.
  4. Consider replacing the throw with `CoerceValueCallback` that clamps the value, so invalid input degrades gracefully instead of throwing.

Example fix

// before
<mdtc:Clock MinuteSelectionStep="7" /> <!-- throws -->

// after
<mdtc:Clock MinuteSelectionStep="5" />
Defensive patterns

Strategy: validation

Validate before calling

static readonly HashSet<int> ValidSteps =
    new() { 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60 };
int step = desiredStep;
if (!ValidSteps.Contains(step)) step = 1; // safe default
clock.MinuteSelectionStep = step;

Type guard

static bool IsValidMinuteStep(int step)
    => step >= 1 && step <= 60 && 60 % step == 0;

Prevention

When it happens

Trigger: Setting `MinuteSelectionStep` to 0, a value > 60, or a non-divisor of 60 such as 7, 9, 11, 13; providing it via XAML attribute, style setter, or binding.

Common situations: User/designer types `MinuteSelectionStep="7"` in XAML thinking any minute step works; binding to a preference that allows arbitrary ints; copying a value from a 24-hour or seconds-based control.

Related errors


AI-assisted analysis of MaterialDesignInXAML/MaterialDesignInXamlToolkit@98edec3a0b (2026-08-13). Data as JSON: /api/errors/8a04a0f33c4ccd60. Report an issue: GitHub.