Guys, here is a story. The code is a bit simplified not to confuse you
I'm working on an app which will set up UI's behavior and appearance based on user roles. The roles are following:
public enum UserType
{
Standard,
Advanced,
Admin
}
I've got a Main Window which hosts a custom control
<Window x:Class="WPFValidation.MainWindow"
...>
<Grid>
<WPFValidation:PersonView dp:RoleManager.CurrentRole="Admin" />
</Grid>
</Window>
dp:RoleManager.CurrentRole="Admin"
is an attached Dependency Property which should set User Role to Admin so all nested controls should know that the value of the current user is "Admin" (I'll talk about this DP a bit later)
Here is the code for the PersonView:
<UserControl x:Class="WPFValidation.PersonView"
...>
<Grid>
<Button dp:RoleManager.EnabledRoles="Admin,Advanced" />
</Grid>
</UserControl>
which means that only Admin or Advanced users can click this button
(I skip ICommand's implementation and so on to keep the example simple)
And finally, the code for CurrentRole and EnabledRoles DependencyProperties
public class RoleManager: DependencyObject
{
public static readonly DependencyProperty CurrentRoleProperty =
DependencyProperty.RegisterAttached("CurrentRole",
typeof (UserType),
typeof (RoleManager),
new FrameworkPropertyMetadata(UserType.Standard,FrameworkPropertyMetadataOptions.Inherits)
public static void SetCurrentRole (DependencyObject element, UserType value)
{
if (element!=null)
element.SetValue(CurrentRoleProperty, value);
}
public static UserType GetCurrentRole (DependencyObject element)
{
return element != null ?
(UserType)element.GetValue(CurrentRoleProperty)
: default(UserType);
}
public static readonly DependencyProperty EnabledRolesProperty =
DependencyProperty.RegisterAttached
("EnabledRoles",
typeof(string),
typeof(RoleManager),
new PropertyMetadata((s, e) => OnEnabledRolesChanged(s)));
public static void SetEnabledRoles(DependencyObject obj, string value)
{
var element = obj as UIElement;
if (element != null)
element.SetValue(EnabledRolesProperty, value);
}
public static string GetEnabledRolesRoles(DependencyObject obj)
{
var element = obj as UIElement;
return element != null ? (string)obj.GetValue(EnabledRolesProperty) : null;
}
public static void OnEnabledRolesChanged(DependencyObject sender)
{
var element = sender as UIElement;
if (element != null)
{
var stringRoles = new List<string>(((string)(element.GetValue(EnabledRolesProperty))).Split(','));
List<UserType> roles =
stringRoles.Select(p => StringToEnumConverter.GetEnumFromString<UserType>(p.Trim())).ToList();
var currentRole = GetCurrentRole(element);
element.IsEnabled = roles.Contains(currentRole);
}
}
#endregion
}
So, essentially, the value of the attached DP does not propagate to it's "children".
When I set the CurrentRole for the button explicitly
<Button dp:RoleManager.CurrentRole="Admin" dp:RoleManager.EnabledRoles="Admin,Advanced" />
, everything worked fine, but it is not what I want. I'd like that attached DP to be set up once at the topmost level, so all the children can use its value.
Any suggestions/ideas/critisism is greatly appreciated