Note that there are some explanatory texts on larger screens.

plurals
  1. POAttachedProperty in XAML firing before I can authenticate & determine role
    text
    copied!<p>Using VS2008, Silverlight 4.</p> <p>I have created an AttachedProperty, "RequiresRole", that I'm setting in my XAML. If a user isn't in the role defined by that property, the visibility of said control is set to collapsed. </p> <p>The problem I'm currently having is that the 'UserHasRole' check (within my Authorization class, as part of the RequiredRole_Callback function) is firing when I load the application, but before I have a chance to login, authenticate, and set the Role for the user. So the property is working, because the menu item is not visible, but it's not currently alerting my UI, after authentication, that the role has changed. I know where to implement it, just not how. INotifyPropertyChanged? Not sure how that'd fit.</p> <p>I have a few properties in my App.xaml.cs, "IsAuthenticated", which is set to true when a user logs in (using a service to call a SPROC), and "Role", which is the return value of a successful call to Logon SPROC.</p> <p>Relevant Authorization.cs code: </p> <pre><code>public static readonly DependencyProperty RequiredRoleProperty = DependencyProperty.RegisterAttached( "RequiredRole", typeof(string), typeof(Authorization), new PropertyMetadata(RequiredRole_Callback)); // This callback will be invoked when some control will receive a value for your 'RequiredRole' property private static void RequiredRole_Callback(DependencyObject source, DependencyPropertyChangedEventArgs e) { var uiElement = (UIElement)source; RecalculateControlVisibility(uiElement); // also this class should subscribe somehow to role changes and update all control's visibility after role being changed } private static void RecalculateControlVisibility(UIElement control) { //Authorization.UserHasRole() - is your code to check roles if (Authorization.UserHasRole(GetRequiredRole(control))) control.Visibility = Visibility.Visible; else control.Visibility = Visibility.Collapsed; } private static Boolean UserHasRole(string role) { string Role = App.Role; if (Role.ToLower() == role.ToLower()) { return true; } return false; } </code></pre> <p>Relevant MainPage.xaml code: </p> <pre><code>xmlns:s="clr-namespace:TSMVVM.Authorization" &lt;HyperlinkButton x:Name="lnkLogin" HorizontalAlignment="Right" Tag="Login" Command="{Binding NavigateCommand}" s:Authorization.RequiredRole="Azdmin" CommandParameter="{Binding Tag, ElementName=lnkLogin}" Content="Login" /&gt; </code></pre> <p>Relevant Mainpage.xaml.cs code:</p> <pre><code>void MainPage_Loaded(object sender, RoutedEventArgs e) { if (!App.IsAuthenticated) { ContentFrame.Navigate(new Uri("Login", UriKind.Relative)); } } </code></pre> <p><strong>Updated Code</strong> (Note, changed RequiredRole to RequiresRole) Authorization.cs</p> <pre><code>public class Authorization { #region Attached DP registration public static string GetRequiresRole(UIElement obj) { return (string)obj.GetValue(RequiresRoleProperty); } public static void SetRequiresRole(UIElement obj, string value) { obj.SetValue(RequiresRoleProperty, value); } #endregion /// Using a DependencyProperty as the backing store for requiresRole. This enables animation, styling, binding, etc... public static readonly DependencyProperty RequiresRoleProperty = DependencyProperty.RegisterAttached( "RequiresRole", typeof(string), typeof(Authorization), new PropertyMetadata(RequiresRole_Callback)); // This callback will be invoked when some control will receive a value for your 'RequiredRole' property private static void RequiresRole_Callback(DependencyObject source, DependencyPropertyChangedEventArgs e) { var uiElement = (UIElement)source; if (App.IsAuthenticated) { RecalculateControlVisibility(uiElement); } else { EventHandler eh = null; eh = delegate { RecalculateControlVisibility(uiElement); ((App)Application.Current).Authenticated -= eh; }; ((App)Application.Current).Authenticated += eh; } } private static void RecalculateControlVisibility(UIElement control) { //Authorization.UserHasRole() - is your code to check roles if (Authorization.UserHasRole(GetRequiresRole(control))) control.Visibility = Visibility.Visible; else control.Visibility = Visibility.Collapsed; } private static Boolean UserHasRole(string role) { if (App.Role != null) { string Role = App.Role[0].ToString(); if (Role.ToLower() == role.ToLower()) { return true; } } return false; } } </code></pre> <p>App.xaml.cs</p> <pre><code>private static string _role; public event EventHandler Authenticated = delegate { }; public static string Role { get { return _role; } set { _role = value; } } </code></pre> <p>MainPage.xaml:</p> <pre><code>&lt;HyperlinkButton x:Name="lnkSiteParameterDefinitions" Style="{StaticResource LinkStyle}" Tag="SiteParameterDefinitions" s:Authorization.RequiresRole="Admin" Content="Site Parameter Definitions" Command="{Binding NavigateCommand}" CommandParameter="{Binding Tag, ElementName=lnkSiteParameterDefinitions}"/&gt; </code></pre> <p>And finally, login.xaml.cs</p> <pre><code>private void LogonService_LogonCompleted(object sender, TSMVVMLogonSVC.LogonCompletedEventArgs e) { ObservableCollection&lt;string&gt; Result = e.Result; switch (Result[0]) { case "Logon Failed": break; case "Logon Successful": PageConductor = new Services.PageConductor(); App.CurrentUser = Result[2]; App.Role = Result[1].ToString(); App.IsAuthenticated = true; Messenger.Default.Send(new TSMVVM.Messages.FrameMessage() { RootFrame = (Frame)this.Parent}); PageConductor.GoToView("Home", "main"); break; case "Change Password": break; } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload