Tuesday, April 13, 2010

Create enum based Collection Dependency Properties and set them declaratively in XAML

I was recently updating a Silverlight web part that involved a very complicated form. I came across a scenario where I needed to determine a user’s SharePoint group and then disable or enable a user control according to their permissions. I already had code that passed the user’s credentials and mapped the custom SharePoint groups to an enum. Since there were many databound controls with many different permissions, the main goal was to be able to easily set these permissions declaratively within XAML.

Ultimately, I wanted something that looked like the following. In this example, only a Manager or Supervisor have access to edit the control. The CurrentGroup property is databound and if it returned anything other than Manager or Supervisor, the control would be disabled.

        <localCtrl:MyPermissionTextBox x:Name="permissionCtrl" CurrentGroup="{Binding CurrentGroup}">
<
localCtrl:MyPermissionTextBox.PermissionGroups>
<
localCtrl:PermissionGroupItem Group="Manager" />
<
localCtrl:PermissionGroupItem Group="Supervisor" />
</
localCtrl:MyPermissionTextBox.PermissionGroups>
</
localCtrl:MyPermissionTextBox>


In a nutshell, you will want to do the following steps:



1. Create an item class that encapsulates your enum and stores it as a property.

2. Create a collection class that derives from ObservableCollection<T> (where T is the item class type). Add a read-only property that retrieves your list of enums into a a generic list.


3. Add a UserControl that has two dependency properties: one for the collection class, and one for the current group.


4. In the UserControl’s Loaded event handler, disable or enable the control by checking if the current group is in the list of groups for the control.


5. Add the UserControl to a layout page and set all of the properties in XAML.



Permission UserControl XAML


1. Add a Silverlight UserControl to your project. I named mine “MyPermissionTextBox”.

2. Update the XAML to include a Loaded event handler for the UserControl and a TextBox control with the name “MyControl”.



<UserControl x:Class="MyProject.Controls.MyPermissionTextBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" Loaded="UserControl_Loaded">
<
Grid x:Name="LayoutRoot" Background="White">
<
TextBox Name="MyControl" Width="150" Height="20" />
</
Grid>
</
UserControl>



Permission UserControl Code Behind



using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

namespace MyProject.Controls
{
public enum PermissionGroup { Viewer, Member, Manager, SrManager, Supervisor, Admin }

public partial class MyPermissionTextBox : UserControl
{
public static readonly DependencyProperty PermissionGroupsProperty =
DependencyProperty.Register("PermissionGroups", typeof(PermissionGroupItemCollection), typeof(MyPermissionTextBox),
new PropertyMetadata(null, OnPermissionGroupsPropertyChanged));

private static void OnPermissionGroupsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyPermissionTextBox source = (MyPermissionTextBox)d;
source.PermissionGroups = (PermissionGroupItemCollection)e.NewValue;
}

public PermissionGroupItemCollection PermissionGroups
{
get
{
if (GetValue(PermissionGroupsProperty) == null)
{
return new PermissionGroupItemCollection();
}
else
{
return (PermissionGroupItemCollection)GetValue(PermissionGroupsProperty);
}
}
set
{
if (value is PermissionGroupItemCollection)
{
MyControl.IsEnabled = ((PermissionGroupItemCollection)value).Values.Contains(CurrentGroup);
SetValue(PermissionGroupsProperty, value);
}
else
{
MyControl.IsEnabled = false;
}
}
}

public static readonly DependencyProperty CurrentGroupProperty =
DependencyProperty.Register("CurrentGroup", typeof(PermissionGroup), typeof(MyPermissionTextBox),
new PropertyMetadata(PermissionGroup.Viewers, OnCurrentGroupPropertyChanged));

private static void OnCurrentGroupPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyPermissionTextBox source = (MyPermissionTextBox)d;
source.CurrentGroup = (PermissionGroup)e.NewValue;
}

public PermissionGroup CurrentGroup
{
get
{
return (PermissionGroup)GetValue(CurrentGroupProperty);
}
set
{
SetValue(CurrentGroupProperty, value);
}
}

public MyPermissionTextBox()
{
InitializeComponent();
PermissionGroups = new PermissionGroupItemCollection();
}

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
MyControl.IsEnabled = PermissionGroups.Values.Contains(CurrentGroup);
}
}

public class PermissionGroupItem
{
public PermissionGroup Group { get; set; }
}

public class PermissionGroupItemCollection : ObservableCollection<PermissionGroupItem>
{
public List<PermissionGroup> Values
{
get
{
return (from n in this.Items select n.Group).ToList();
}
}
}
}



Test UserControl XAML



Note: You will need to handle the Binding for CurrentGroup. In this example I have simply hard-coded. In this case the control would be disabled as the Viewer is not in the list of Permissions.




<UserControl x:Class="MyProject.Controls.Test"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:local="clr-namespace:MyProject"

xmlns:localCtrl="clr-namespace:MyProject.Controls" Height="300"Width="300">

<
Grid x:Name="LayoutRoot"Background="White"HorizontalAlignment="Stretch">

<
localCtrl:MyPermissionTextBox x:Name="permissionCtrl"CurrentGroup="Viewer">

<
localCtrl:MyPermissionTextBox.PermissionGroups>

<
localCtrl:PermissionGroupItem Group="Manager" />

<
localCtrl:PermissionGroupItem Group="Supervisor" />

</
localCtrl:MyPermissionTextBox.PermissionGroups>

</
localCtrl:MyPermissionTextBox>

<
TextBlock FontSize="10">

<
TextBlock.Style>

<
Style>

<
SetterProperty="FontSize"Value="10" />

</
Style>

</
TextBlock.Style>

</
TextBlock>

</
Grid>

</
UserControl>



Note: All code done in Visual Studio 2010 RTM.


No comments:

Post a Comment