wpf动态用户安全

时间:2019-01-05 22:58:49

标签: wpf tags visibility wpf-style

该软件使用SmartSnowUser对象,其中包含SecurityRole对象。客户端需要可自定义的SecurityRole,因此它具有枚举SecurityTasks的列表,客户端可以从中添加/删除。仅当控件的给定SecurityTask存在于当前SmartSnowUser的控件中时,控件才应该可见 SecurityRole。

通过此设置,我正在努力获得所需的所有功能。 我需要具备以下能力:

  • 根据CurrentUser.Role是否包含GivenTask更改控件可见性
  • 在必要时使控件的可见性更加精细(例如Visibility&= isInEditMode)
  • 满足前两项要求,而不必为每种颜色/任务/额外限定词组合创建单独的样式

这是我尝试过的两种主要方法。

尝试#1:

Wpf User Security Strategy

当前问题:可见性未触发;永远不会碰到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:

How to extend instead of overriding WPF Styles

How to add dependency property to FrameworkElement driven classes in WPF?

试图将这两种解决方案合并为一个。将Tag值设置为SecurityTask,然后使用触发器设置可见性

issue:如果没有样式,则无法在更详细的级别上设置可见性(例如,无法直接在控件中设置“ Visibility”属性);无法区分可见性/可编辑性

代码:

/**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 ALMOST起作用。这就是最后一个令人讨厌的按钮,BtnEdit。每次我需要向可见性设置中添加另一个限定符时,创建新样式-BaselyOn ButtonBlue,BasedOn ButtonDefault,BaseOnBase太容易了。

我似乎过于复杂了。是否有更干净的方法来解决我的问题?

0 个答案:

没有答案