wpf динамическая безопасность пользователя - PullRequest
0 голосов
/ 06 января 2019

Программное обеспечение использует объект SmartSnowUser, который содержит объект SecurityRole. Клиенту необходимо настроить SecurityRole, поэтому у него есть список перечисленных SecurityTasks, которые клиенты могут добавлять / удалять. Элементы управления должны быть видимы, только если их заданная SecurityTask существует в текущем SmartSnowUser's SecurityRole.

С этой настройкой я изо всех сил пытаюсь получить всю необходимую функциональность. Мне нужна способность:

  • изменить видимость элемента управления в зависимости от того, содержит ли CurrentUser.Role GivenTask
  • делает видимость элемента управления более детальной, когда это необходимо (например, Visibility & = isInEditMode)
  • соответствует двум предыдущим требованиям без необходимости создания отдельного стиля для каждой комбинации цвет / задание / дополнительный квалификатор

Вот два основных подхода, которые я попробовал.

Попытка № 1:

Стратегия безопасности пользователя Wpf

Текущая проблема: видимость не срабатывает; точка останова в методе Convert () никогда не достигает

Долгосрочная проблема: использует стиль, поэтому каждый другой пользовательский стиль должен быть основан на этом значении по умолчанию; также, для возможности редактирования необходимо дублировать функциональность

Код:

/**Style.xaml**/
<local:TagToVisibilityConverter x:Key="TagToVisibilityConverter"/>
<Style TargetType="{x:Type FrameworkElement}">
    <Setter Property="Visibility">
        <Setter.Value>
            <MultiBinding Converter="{StaticResource TagToVisibilityConverter}">
                <Binding Path="MainData.CurrentUser"/>
                <Binding RelativeSource="{RelativeSource Mode=Self}"/>
            </MultiBinding>
        </Setter.Value>
    </Setter>
</Style>

/**Style.xaml.cs**/
public class TagToVisibilityConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values.Length >= 2 && (values[1] as FrameworkElement).GetValue(SecurityLevel.RequiredTaskProperty) is SecurityTask requiredTask)
        {
            //If element has a task assigned and user is not logged in, do not show
            if (values[0] is SmartSnowUser currentUser && currentUser.Role != null)
            {
                return currentUser.Role.Tasks.Contains(requiredTask) ? Visibility.Visible : Visibility.Collapsed;
            }
            return Visibility.Collapsed;
        }

        //If element has no task assigned, default to visible
        return Visibility.Visible;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

public class SecurityLevel
{
    public static readonly DependencyProperty RequiredTaskProperty = DependencyProperty.RegisterAttached("RequiredTask", typeof(SecurityTask), typeof(FrameworkElement), new PropertyMetadata(SecurityTask.ControlBasic));
    public static void SetRequiredTask(UIElement element, SecurityTask value)
    {
        element.SetValue(RequiredTaskProperty, value);
    }

    public static SecurityTask GetRequiredTask(UIElement element)
    {
        return (SecurityTask)element.GetValue(RequiredTaskProperty);
    }
}

/**Implementation in User Control**/
<Button Name="BtnNew" Content="Create New Role" Style="{StaticResource ButtonBlue}" server:SecurityLevel.RequiredTask="{x:Static enums:SecurityTask.EditRoles}" />


Попытка № 2:

Как расширить вместо переопределения стилей WPF

Как добавить свойство зависимостей в управляемые классы FrameworkElement в WPF?

Попытка объединить эти два решения в одно. Установите значение тега SecurityTask, затем используйте триггер, чтобы установить видимость

проблема: невозможно установить видимость на более детальном уровне без стиля (например, нельзя установить свойство «Видимость» непосредственно в элементе управления); не может различить видимость / редактируемость

Код:

/**Style.xaml**/
<!--#region Visibility-->
<!-- Default frameworkElement style definition -->
<local:TagToVisibilityConverter x:Key="TagToVisibilityConverter"/>
<Style TargetType="{x:Type FrameworkElement}">
    <Setter Property="Visibility">
        <Setter.Value>
            <MultiBinding Converter="{StaticResource TagToVisibilityConverter}">
                <Binding Path="Tag" RelativeSource="{RelativeSource Mode=Self}"/>
                <Binding Path="MainData.CurrentUser"/>
            </MultiBinding>
        </Setter.Value>
    </Setter>
</Style>

<!-- Extending default style -->
<Style x:Key="ButtonBasic" TargetType="Button" BasedOn="{StaticResource {x:Type FrameworkElement}}">
    <Setter Property="Background" Value="{StaticResource BrushGreyDark}" />
    <Setter Property="Foreground" Value="{StaticResource BrushWhite}" />
</Style>

<Style x:Key="ButtonBlue" TargetType="Button" BasedOn="{StaticResource ButtonBasic}">
    <Setter Property="Background" Value="{StaticResource BrushBlue}" />
</Style>

/**Style.xaml.cs**/
public class TagToVisibilityConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values.Length >= 2 && values[0] is SecurityTask requiredTask)
        {
            //If element has a task assigned and user is not logged in, do not show
            if (values[1] is SmartSnowUser currentUser && currentUser.Role != null)
            {
                return currentUser.Role.Tasks.Contains(requiredTask) ? Visibility.Visible : Visibility.Collapsed;
            }

            return Visibility.Collapsed;
        }

        //If element has no task assigned, default to visible
        return Visibility.Visible;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

/**Implementation in User Control**/
//This button works great. Exactly what I need.
<Button Name="BtnNew" Content="Create New Role" Style="{StaticResource ButtonBlue}" Tag="{x:Static enums:SecurityTask.EditRoles}" />

//This button does not work, because the newly set Visibility property overrides the style. 
<Button Name="BtnEdit" Content="Edit Role" Style="{StaticResource ButtonBlue}" Tag="{x:Static enums:SecurityTask.EditRoles}" Visibility="{Binding IsEditMode, Converter={StaticResource InverseBoolToVisibilityConverter}}" />

Попытка № 2 ПОЧТИ работает. Это последняя вонючая кнопка, BtnEdit. Он слишком загроможден, чтобы создавать новый стиль - BasedOn ButtonBlue, который называется BasedOn ButtonDefault, который основан на нашем оригинале, - каждый раз, когда мне нужно добавить еще один классификатор в настройки видимости.

Кажется, я слишком усложняю это. Есть ли более чистый подход к тому, что я пытаюсь сделать?

...