I have an UserControl
where I declare two DependencyProperties
int? Level;
CardBase SelectedCardBase;
A non-null CardBase
object will always have 2 read-only integers
: MinLevel
and MaxLevel
.
The UserControl
allows the user to change as he desires both DPs, and the internal logic must ensure that both DPs have valid values following these rules:
- If
SelectedCardBase
is null, thenLevel
must be null. - If
SelectedCardBase
is not null, thenLevel
must be betweenMinLevel
andMaxLevel
. - When
SelectedCardBase
changes to anything butnull
,Level
is set toMaxLevel
.
This is the code:
public CardBase SelectedCardBase
{
get { return (CardBase)GetValue(SelectedCardBaseProperty); }
set { SetValue(SelectedCardBaseProperty, value); }
}
public static readonly DependencyProperty SelectedCardBaseProperty =
DependencyProperty.Register("SelectedCardBase", typeof(CardBase), typeof(MyUserControl),
new PropertyMetadata(null, new PropertyChangedCallback(SelectedCardBaseChanged)));
private static void SelectedCardBaseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == null)
d.SetValue(LevelProperty, null);
else
d.SetValue(LevelProperty, ((CardBase)e.NewValue).MaxLevel);
}
public int? Level
{
get { return (int?)GetValue(LevelProperty); }
set { SetValue(LevelProperty, value); }
}
public static readonly DependencyProperty LevelProperty =
DependencyProperty.Register("Level", typeof(int?), typeof(MyUserControl),
new PropertyMetadata(null, new PropertyChangedCallback(LevelChanged)));
private static void LevelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CardBase card = (CardBase)d.GetValue(SelectedCardBaseProperty);
if (card == null)
{
if (e.NewValue != null)
d.SetValue(LevelProperty, null);
}
else if (e.NewValue == null)
{
d.SetValue(LevelProperty, e.OldValue);
}
else
{
int level = (int)e.NewValue;
if (level < card.MinLevel)
d.SetValue(LevelProperty, card.MinLevel);
else if (level > card.MaxLevel)
d.SetValue(LevelProperty, card.MaxLevel);
}
}
I don't fully get how CoerceValueCallbacks
work, and I've read (or misunderstood) that both Coerce and Changed callbacks can be overwritten because they are metadata, so my questions are:
- What problems (if they exist) will I have when something subscribes to the OnValueChanged of one of those DP?
- Should I use CoerceValueCallbacks instead of this?
- If so, what is the correct way of doing this using CoerceValueCallbacks?
- And of course, with the given rules at the beginning, there is any mistake on the code that would cause strange behaviour, or anything that could be improved?
1 Answer 1
Yes, you should use CoerceValueCallback
instead to coerce your Level property (what you are trying to do is not "validation" strictly speaking).
private static object CoerceLevel(DependencyObject d, object value)
{
var control = (MyUserControl)d;
if (control.SelectedCard == null) return null;
var level = (int?)value;
if (level.HasValue)
{
return Math.Min(Math.Max(level.Value, control.SelectedCard.MinLevel), control.SelectedCard.MaxLevel);
}
else
{
return control.Level;
//or
//return DependencyProperty.UnsetValue;
}
}
-
\$\begingroup\$ Will this be called automatically whenever the Level is set? \$\endgroup\$Guillermo Mestre– Guillermo Mestre2015年01月29日 13:42:18 +00:00Commented Jan 29, 2015 at 13:42
-
\$\begingroup\$ @GuillermoMestre, yes, if you add this calllback to your dependency property declaration. \$\endgroup\$Nikita B– Nikita B2015年01月29日 13:50:50 +00:00Commented Jan 29, 2015 at 13:50
-
\$\begingroup\$ And the CardChangedCallback should remain as it is, right? \$\endgroup\$Guillermo Mestre– Guillermo Mestre2015年01月29日 13:55:10 +00:00Commented Jan 29, 2015 at 13:55
-
\$\begingroup\$ @GuillermoMestre, pretty much, yes. You should use
PropertyChangedCallback
, when you want to change other proprties, andCoerceValueCallback
when you want to alter the changed property itself. You might want to cast first argument toMyUserControl
and use regular properties though.d.SetValue
calls do not look pretty. \$\endgroup\$Nikita B– Nikita B2015年01月29日 14:01:03 +00:00Commented Jan 29, 2015 at 14:01 -
\$\begingroup\$ @GuillermoMestre, you can read more on msdn msdn.microsoft.com/en-us/library/ms745795%28v=vs.110%29.aspx \$\endgroup\$Nikita B– Nikita B2015年01月29日 14:05:17 +00:00Commented Jan 29, 2015 at 14:05
DependencyPropertyManager.Register
has an explicit override for providing a Validation callback? msdn.microsoft.com/en-us/library/ms597501(v=vs.110).aspx \$\endgroup\$