【问题标题】:Can I have two Web User Controls (.ascx) share the same codebehind class?我可以让两个 Web 用户控件 (.ascx) 共享同一个代码隐藏类吗?
【发布时间】:2015-01-06 11:54:43
【问题描述】:

我有一种情况,我需要为 Web 用户控件提供两种完全不同的布局,但控件的代码隐藏保持相同非常重要。

有什么方法可以为两个不同的 Web 用户控件使用相同的代码隐藏?我尝试将 Page 指令更改为使用相同的类,但偶尔在构建时,会生成带有重复控件的 .designer.cs 文件,因此会出现编译错误。

我也尝试过从一个公共基类继承,但是你看不到这个类的任何控件,这使得采用这种方法非常困难。

或者有没有办法防止为“克隆”控件重新生成 Designer.cs 类?

【问题讨论】:

  • 代码隐藏中有很多业务逻辑吗?如果是这样,是否可以将其放在单独的类中并由代码隐藏用于您的两个用户控件?
  • 不是“业务逻辑”本身 - 而是验证控件和处理输入等工作。因为此代码大量访问控件,并且您无法从基类中看到控件,所以我没有认为这将是解决问题的一个很好的方法:(
  • 您可以创建一个包含包含验证逻辑的方法的静态类,而不是基类。这些方法将作为参数传递给您的控件的引用。

标签: c# asp.net webusercontrol


【解决方案1】:

创建基类,并在那里实现通用逻辑。然后从这个基类继承控件。为了从基类级别访问控件,请在基类级别为您需要的每个控件抽象获取属性。在子控件类中实现这些属性。

public abstract class BaseControl : UserControl
{
  public abstract TextBox FirstName { get; }

  public void SomeLogicExample() 
  {
    FirstName.Text = "Something"; 
  }
}

public class ControlA : BaseControl
{
  public override TextBox FirstName
  {
    // txtFirstNameA is ID of TextBox, so it is defined in ControlA.designer.cs
    get { return txtFirstNameA; }
  }
}

public class ControlB : BaseControl
{
  public override TextBox FirstName
  {
    // txtFirstNameB is ID of TextBox, so it is defined in ControlB.designer.cs
    get { return txtFirstNameB; }
  }
}

另外一种不太优雅的是在运行时定位控件;因为您为搜索整个控件树付费,并且您必须处理未找到控件的情况:

public abstract class BaseControl : UserControl
{
  public T GetControlByType<T>(Func<T, bool> predicate = null) where T : Control
  {
    var stack = new Stack<Control>(new Control[] { this });
    while (stack.Count > 0)
    {
      var control = stack.Pop();
      T match = control as T;
      if (match != null)
      {
        if (predicate == null || predicate(match))
        {
          return match;
        }
      }

      foreach (Control childControl in control.Controls)
      {
        stack.Push(childControl);
      }
    }

    return default(T);
  }    

  public TextBox FirstName
  {
    get { return GetControlByType<TextBox>(t => t.ID == "txtFirstName"); }
  }

  public void SomeLogicExample() 
  {
    FirstName.Text = "Something"; 
  }
}

【讨论】:

  • 感谢您的回复,但我选择了我接受的答案,因为它更简单,只需按下删除键;)
  • @NickG 我强烈建议您重新考虑您的决定,您正在搞乱并更改默认的 asp.net / VS 行为,从长远来看这可能会导致更多麻烦。
【解决方案2】:

我刚刚在 VS 2012 中对此进行了测试。

  1. 我添加了 2 个用户控件
  2. 从第二个控件中删除了.ascx.cs.ascx.Designer.cs 文件
  3. 修改了CodeBehindInherits 属性的第二个控件的Page 指令。无需为第二个控件生成 Designer 文件。

而且它有效。我不知道这是否有效。 我通过在每个控件中添加一个Label 并在后面的代码中设置它的值来测试它。该值反映在两个控件中。

当您在一个用户控件中有一个 asp.net 控件而在另一个用户控件中不存在时,您可能会遇到问题。

【讨论】:

  • 执行此操作时,有时会重新填充 .designer.cs 文件(我不知道何时!)。
  • .designer.cs 只有在您尝试将其转换为 Web 应用程序选项时才会重新生成。但是使用这种方法,您无法为上述控件生成.designer.cs,并且在转换时会引发错误。其余功能将按原样工作。试试看。
  • 谢谢你是对的。关键似乎是删除文件而不是清空它。这样 .designer.cs 就不会被重新创建。
【解决方案3】:

除了@Ondrej Svejdar 的正确答案之外,我建议您查看MVP design pattern 并可能将其与您的Web 表单代码一起使用。它有效,我在一个大项目中尝试过,结果并不比 MVC 项目中的关注点分离差。有一些框架可以帮助您实现它,但出于某种原因,我更喜欢自己实现它(毕竟它是几个基类和一个基接口)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    • 1970-01-01
    • 2012-01-16
    • 1970-01-01
    • 2019-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多