Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# VS2013 WinForms designer的IExtenderProvider问题 简明的_C#_Winforms_Iextenderprovider - Fatal编程技术网

C# VS2013 WinForms designer的IExtenderProvider问题 简明的

C# VS2013 WinForms designer的IExtenderProvider问题 简明的,c#,winforms,iextenderprovider,C#,Winforms,Iextenderprovider,我正在实现IExtenderProvider,以便为winforms控件提供一个属性,以存储每个控件的权限集合,这些权限必须被授予才能使控件可用 问题 一切都按预期运行良好,问题只出现在设计阶段,并且只有在以下情况下: 我打开表单设计器。 表单上某些控件的编辑权限扩展属性。 在窗体设计器打开时编译我的项目。 然后,在编译之后,如果我再次尝试编辑控件的权限,权限将消失,尽管它们仍然存在于表单的desiger.cs文件中 此外,如果在此状态下执行任何导致重新生成设计器文件的设计器操作(例如,移动按钮

我正在实现IExtenderProvider,以便为winforms控件提供一个属性,以存储每个控件的权限集合,这些权限必须被授予才能使控件可用

问题 一切都按预期运行良好,问题只出现在设计阶段,并且只有在以下情况下:

我打开表单设计器。 表单上某些控件的编辑权限扩展属性。 在窗体设计器打开时编译我的项目。 然后,在编译之后,如果我再次尝试编辑控件的权限,权限将消失,尽管它们仍然存在于表单的desiger.cs文件中

此外,如果在此状态下执行任何导致重新生成设计器文件的设计器操作(例如,移动按钮),则表单设计器文件中的权限将丢失

因此,只要我在设计器打开时不编译,一切都正常,我可以编辑权限、保存并再次编辑

要从此状态恢复,请执行以下操作:即,再次从designer.cs文件加载权限

关闭表单设计器并重新打开它。 或者在设计器仍处于打开状态时切换到designer.cs文件,编辑任何内容,然后将其撤消,然后再次返回表单设计器。它将被刷新并再次加载权限。 更新1 感谢@Hans Passant的提示,duh,我在调试设计器时没有检查CLR异常,因此,异常被默默地抑制了

该问题存在于序列化程序的序列化方法中,该方法稍微细化了一点:

public override object Serialize(IDesignerSerializationManager manager, object value)
{
    CodeDomSerializer baseClassSerializer = manager.GetSerializer(typeof(PermissionExtenderProvider).BaseType, typeof(CodeDomSerializer)) as CodeDomSerializer;
    CodeStatementCollection statements = baseClassSerializer.Serialize(manager, value) as CodeStatementCollection;

    try
    {
        PermissionExtenderProvider provider = (PermissionExtenderProvider)value;
        IDesignerHost host = (IDesignerHost)manager.GetService(typeof(IDesignerHost));
        var components = host.Container.Components.Cast<IComponent>().Where(x => provider.CanExtend(x));
        this.SerializeExtender(manager, provider, host, components, statements);
    }
    catch(Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }

    return statements;
}
value属性的类型相同,它是PermissionExtenderProvider,但来自不同的源程序集,因此引发以下异常:

System.InvalidCastException: 
[A]VSDesignerExtenderProviderIssue.PermissionExtenderProvider cannot be cast to 
[B]VSDesignerExtenderProviderIssue.PermissionExtenderProvider.
Type A originates from 'VSDesignerExtenderProviderIssue, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither' at location 'C:\Users\Administrator\AppData\Local\Microsoft\VisualStudio\12.0\ProjectAssemblies\elo5dzxu01\VSDesignerExtenderProviderIssue.exe'. 
Type B originates from 'VSDesignerExtenderProviderIssue, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither' at location 'C:\Users\Administrator\AppData\Local\Microsoft\VisualStudio\12.0\ProjectAssemblies\5_6og8t_01\VSDesignerExtenderProviderIssue.exe'.
由于这个问题是在编译后才出现的,我想从现在开始就有问题了

我不完全确定设计器进程,但我的解释是,值是从以前编译的程序集中传递的,然后我尝试转换为驻留在设计器使用的活动程序集中的相同类型,因此无法执行转换,因为类型来自两个不同的程序集

为什么它从不同的程序集发送值?在不手动将对象映射/序列化到活动程序集类型的情况下,是否可以解决此问题

代码 我尝试过在编译后的状态下(即问题发生时)在设计模式下调试它,但我能想到的是PermissionExtenderProvider.GetPermissions。。。我的扩展程序提供程序中的方法返回null,这意味着PermissionExtenderProvider.SetPermission。。。尚未调用,因此PermissionCollectionEditor.EditValue。。。在我的自定义UITypeEditor中,接收空值并将其传递给PermissionCollectionEditorForm,这就是权限不存在的原因

我提供了一个演示该问题的小样本项目,它包括:

包含示例权限的权限文件夹。 许可证收集 PermissionCollectionEditor UITypeEditor实现。 PermissionCollectionEditor表单编辑权限集合属性的表单。 PermissionExtenderProvider提供权限属性的IExtenderProvider实现。 PermissionExtenderProviderSerializer将扩展属性序列化为设计器文件的序列化程序。 Form1是项目的主窗体,带有一些具有测试权限的按钮。 您可以使用具有一些按钮的Form1和PermissionExtenderProvider实例测试扩展器

以下是该项目的一些关键代码:

许可收集编辑器

许可证扩展程序提供程序

来自初始帖子的背景信息 我有一个winforms应用程序,具有与数据库交互的中间服务层

在数据库中,我有一些表,这些表定义并映射用户和用户角色的权限。这些权限在我的应用程序的类中表示,并实现IPermission

在我的应用程序中,我有一个PermissionProvider类,它调用服务并检查用户的权限,以禁用/隐藏用户不必访问的任何控件,当然,我不依赖于此来实现安全性

我想做的是,通过添加Permissions属性来扩展Winforms控件,这是一个权限集合,所以我使用了IExtenderProvider

我已经实现了自定义UITypeEditor来编辑属性,并实现了自定义UITypeEditor来在设计器文件中正确序列化权限集合

我还在我的扩展程序提供程序中添加了一个名为Host的属性,该属性存储承载提供程序的表单/用户控件,并由我的自定义序列化程序在设计器文件中序列化它以及权限

然后,在我的提供程序中,当设置host属性时,我订阅host窗体/用户控件的Load事件,并在运行时加载主机时验证控件的权限,并放置一个小指示器,以便用户知道该控件由于 权限不足


我正在使用Update 4运行VS2013社区,Win 8.1 64位,并使用x86进行编译。

我没有任何答案,但我可以说祝你好运,我自己也在设计器中努力解决序列化问题,这不是一个有趣的过程。我发现删除自定义序列化代码并让设计器完成它的工作是有帮助的,所以我会开始分解东西,直到它正常工作,然后尝试重新添加东西,即使它序列化到resx文件中。@RonBeyer谢谢,我已经尝试了不同的方法,在我提出这个序列化格式之前,我一直面临着很多问题,我认为设计师很满意,很明显,在某种程度上,它不是。我将不得不休假阅读所有内容。Punting:设计时的异常会导致这种行为。启动另一个VS实例,工具+附加到进程以附加到VS的第一个实例。调试>异常>勾选CLR异常以查看它们。@HansPassant我已尝试缩短它。我在调试时没有检查CLR异常,因此异常被抑制。谢谢你的提示。在调试之后,我提出了一些问题,并更新了这个问题。@HansPassant您知道为什么设计器会从不同的程序集传递值吗?
System.InvalidCastException: 
[A]VSDesignerExtenderProviderIssue.PermissionExtenderProvider cannot be cast to 
[B]VSDesignerExtenderProviderIssue.PermissionExtenderProvider.
Type A originates from 'VSDesignerExtenderProviderIssue, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither' at location 'C:\Users\Administrator\AppData\Local\Microsoft\VisualStudio\12.0\ProjectAssemblies\elo5dzxu01\VSDesignerExtenderProviderIssue.exe'. 
Type B originates from 'VSDesignerExtenderProviderIssue, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither' at location 'C:\Users\Administrator\AppData\Local\Microsoft\VisualStudio\12.0\ProjectAssemblies\5_6og8t_01\VSDesignerExtenderProviderIssue.exe'.
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) 
{
    if (context != null && context.Instance != null && provider != null) 
    {
        var editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
        if (editorService != null)
        {
            using (PermissionCollectionEditorForm collEditorFrm = new PermissionCollectionEditorForm(provider, value as PermissionCollection))
            {
                if (editorService.ShowDialog(collEditorFrm) == DialogResult.OK)
                {
                    value = collEditorFrm.Collection;
                }
            }
        }
    }

    return value;
}
[ProvideProperty("Permissions", typeof(IComponent))]
[DesignerSerializer(typeof(PermissionExtenderProviderSerializer), typeof(CodeDomSerializer))]
public class PermissionExtenderProvider : Component, IExtenderProvider 
{
    private Hashtable _Permissions;
    private bool _InitialVerification = false;
    private List<IComponent> _DisabledComponents;

    public PermissionExtenderProvider()
        : base()
    {
        _Permissions = new Hashtable();
        _DisabledComponents = new List<IComponent>();
    }

    //=====================================
    // IExtenderProvider
    //=====================================
    public bool CanExtend(object extendee)
    {
        return (extendee is Control ||
            extendee is TabPage ||
            extendee is ToolStripItem) && !(extendee is PermissionExtenderProvider);
    }

    //=====================================
    // ProvidedProperties
    //=====================================
    [Category("Behavior")]
    [Editor(typeof(PermissionCollectionEditor), typeof(UITypeEditor))]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public PermissionCollection GetPermissions(IComponent component)
    {
        PermissionCollection result = null;
        if (_Permissions.ContainsKey(component))
            result = (PermissionCollection)_Permissions[component];

        return result;
    }

    public void SetPermissions(IComponent component, PermissionCollection value)
    {
        if (value == null)
        {
            value = new PermissionCollection();
        }

        if (value.Count == 0)
        {
            _Permissions.Remove(component);
        }
        else
        {
            _Permissions[component] = value;
        }
    }

    //=====================================
    // Permission verification
    //=====================================
    public bool CheckPermissions(IComponent component)
    {
        PermissionCollection permissions = _Permissions.ContainsKey(component) ? (PermissionCollection)_Permissions[component] : null;
        if (permissions == null)
            return false;

        return PermissionProvider.CheckPermissions(permissions.ToArray());
    }        

    public virtual void AssertPermissions(IComponent component)
    {
        bool hasPermission = CheckPermissions(component);

        if(!hasPermission)
        {
            if(component is TabPage)
            {
                ((TabPage)component).Enabled = false;
                ((TabControl)((TabPage)component).Parent).Invalidate();
            }
            else if(component is ToolStripItem)
            {
                ((ToolStripItem)component).Enabled = false;
            }
            else if(component is Control)
            {
                ((Control)component).Enabled = false;
            }
        }

        // Add/Remove to the list of disabled components
        if(hasPermission && _DisabledComponents.Contains(component))
        {
            _DisabledComponents.Remove(component);
        }
        else if(!hasPermission && !_DisabledComponents.Contains(component))
        {
            _DisabledComponents.Add(component);
        }
    }

    /// <summary>
    /// Verify the permissions associated with the control provider. It hides/disables the controls
    /// associated if the all or any of the permissions are not granted (depending on options specified for the control)
    /// </summary>
    public virtual void VerifyPermissions()
    {
        _DisabledComponents.Clear();

        // Verify the permissions
        foreach (IComponent comp in _Permissions.Keys)
        {
            AssertPermissions(comp);
        }
    }

    //================================================
    // Wiring the host container's load event
    //================================================
    private ContainerControl m_Host;

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public ContainerControl Host
    {
        get { return m_Host; }
        set
        {
            if (m_Host == null && value as Form != null && !DesignMode)
            {
                (value as Form).Load += Initialize;
            }
            else if (m_Host == null && value as UserControl != null && !DesignMode)
            {
                (value as UserControl).Load += Initialize;
            }
            m_Host = value;
        }
    }

    private void Initialize(object sender, EventArgs e)
    {
        if (!DesignMode)
        {
            VerifyPermissions();
            _InitialVerification = true;
        }
    }
}
    public class PermissionExtenderProviderSerializer : CodeDomSerializer
{
    public override object Serialize(IDesignerSerializationManager manager, object value)
    {
        PermissionExtenderProvider provider = value as PermissionExtenderProvider;

        CodeDomSerializer baseClassSerializer = manager.GetSerializer(typeof(PermissionExtenderProvider).BaseType, typeof(CodeDomSerializer)) as CodeDomSerializer;
        CodeStatementCollection statements = baseClassSerializer.Serialize(manager, value) as CodeStatementCollection;

        IDesignerHost host = (IDesignerHost)manager.GetService(typeof(IDesignerHost));
        ComponentCollection components = host.Container.Components;

        this.SerializeExtender(manager, provider, host, components, statements);

        return statements;
    }

    private void SerializeExtender(IDesignerSerializationManager manager, PermissionExtenderProvider provider, IDesignerHost host, ComponentCollection components, CodeStatementCollection statements)
    {
        if (components.Count > 0)
        {
            statements.Add(new CodeCommentStatement(" "));
            statements.Add(new CodeCommentStatement(manager.GetName(provider)));
            statements.Add(new CodeCommentStatement(" "));
        }

        // Set the Host property of the provider, this is where we wire the Load event to assert permissions
        statements.Add(new CodeSnippetStatement(string.Format("this.{0}.Host = this;", manager.GetName(provider))));

        // Serialize permissions for components
        foreach (IComponent component in components)
        {
            if (component is PermissionExtenderProvider
                || component == host.RootComponent)
            {
                continue;
            }

            PropertyDescriptor descriptor = TypeDescriptor.GetProperties(component)["Name"];
            if (descriptor != null)
            {
                CodeMethodInvokeExpression methodcall = new CodeMethodInvokeExpression(base.SerializeToExpression(manager, provider), "SetPermissions");
                string extendeeName = descriptor.GetValue(component).ToString();
                methodcall.Parameters.Add(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), extendeeName));

                PermissionCollection permissions = provider.GetPermissions(component);
                if (permissions != null && permissions.Count > 0)
                {
                    StringBuilder sb = new StringBuilder();

                    // Create new PermissionCollection instance and supply permissions array to constructor
                    sb.Append("new PermissionCollection(");
                    sb.Append("new ");
                    sb.Append(typeof(IPermission).FullName);
                    sb.Append("[] {");

                    foreach (IPermission perm in permissions)
                    {
                        PropertyInfo operationEnumProperty = perm.GetType()
                            .GetProperty("Operation");

                        object operationTypeVal = operationEnumProperty.GetValue(perm, null);
                        string operationTypeEnumValName = Enum.GetName(operationEnumProperty.PropertyType, operationTypeVal);

                        sb.AppendLine();
                        sb.Append("new ");
                        sb.Append(perm.GetType().FullName);
                        sb.Append("(");
                        sb.Append(perm.GetType().FullName);
                        sb.Append(".OperationType.");
                        sb.Append(operationTypeEnumValName);
                        sb.Append(")");
                        sb.Append(", ");
                    }

                    // Remove trailing comma from last item
                    if (permissions.Count > 0)
                    {
                        sb.Remove(sb.Length - 2, 2);
                    }

                    sb.Append(" })");

                    methodcall.Parameters.Add(new CodeSnippetExpression(sb.ToString()));

                }
                else
                {
                    methodcall.Parameters.Add(new CodePrimitiveExpression(null));
                }

                statements.Add(methodcall);
            }
        }
    }
}