我可以让两个 Web 用户控件 (.ascx) 共享同一个代码隐藏类吗?
Can I have two Web User Controls (.ascx) share the same codebehind class?
我遇到这样一种情况,我需要为 Web 用户控件设置两个完全不同的布局,但控件的代码隐藏保持相同非常重要。
有什么方法可以对两个不同的 Web 用户控件使用相同的代码隐藏?我已经尝试更改 Page 指令以使用相同的 class,但偶尔在构建时,会生成一个包含重复控件的 .designer.cs
文件,因此会出现编译错误。
我也试过从一个公共基础 class 继承,但是你看不到这个 class 的任何控件,这使得采用这种方法非常困难。
或者有什么方法可以防止 designer.cs class 为 "clone" 控件重新生成?
创建基础 class,并在那里实现通用逻辑。然后从这个基础继承控件class。要从基础 class 级别访问控件,请为您需要的每个控件在基础 class 级别上抽象获取属性。在子控件中实现这些属性 classes.
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";
}
}
我刚刚在 VS 2012 中对此进行了测试。
- 我添加了 2 个用户控件
- 已从第二个控件中删除
.ascx.cs
和 .ascx.Designer.cs
文件
- 为
CodeBehind
和 Inherits
属性修改了第二个控件的 Page
指令。无需为第二个控件生成 Designer 文件。
并且有效。我不知道这是否有效。
我通过在每个控件中添加一个 Label
并在代码后面设置它的值来测试它。该值反映在两个控件中。
当您在一个用户控件中有一个 asp.net 控件而在另一个用户控件中不存在时,您可能会遇到问题。
除了@Ondrej Svejdar 的正确答案外,我建议您查看 MVP design pattern 并可能将其与您的 Web 窗体代码一起使用。它有效,我在一个大项目中尝试过,结果并不比 MVC 项目中的关注点分离差。有一些框架可以帮助你实现它,但出于某种原因我更喜欢自己实现它(毕竟它是几个基础 类 和一个基础接口)
我遇到这样一种情况,我需要为 Web 用户控件设置两个完全不同的布局,但控件的代码隐藏保持相同非常重要。
有什么方法可以对两个不同的 Web 用户控件使用相同的代码隐藏?我已经尝试更改 Page 指令以使用相同的 class,但偶尔在构建时,会生成一个包含重复控件的 .designer.cs
文件,因此会出现编译错误。
我也试过从一个公共基础 class 继承,但是你看不到这个 class 的任何控件,这使得采用这种方法非常困难。
或者有什么方法可以防止 designer.cs class 为 "clone" 控件重新生成?
创建基础 class,并在那里实现通用逻辑。然后从这个基础继承控件class。要从基础 class 级别访问控件,请为您需要的每个控件在基础 class 级别上抽象获取属性。在子控件中实现这些属性 classes.
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";
}
}
我刚刚在 VS 2012 中对此进行了测试。
- 我添加了 2 个用户控件
- 已从第二个控件中删除
.ascx.cs
和.ascx.Designer.cs
文件 - 为
CodeBehind
和Inherits
属性修改了第二个控件的Page
指令。无需为第二个控件生成 Designer 文件。
并且有效。我不知道这是否有效。
我通过在每个控件中添加一个 Label
并在代码后面设置它的值来测试它。该值反映在两个控件中。
当您在一个用户控件中有一个 asp.net 控件而在另一个用户控件中不存在时,您可能会遇到问题。
除了@Ondrej Svejdar 的正确答案外,我建议您查看 MVP design pattern 并可能将其与您的 Web 窗体代码一起使用。它有效,我在一个大项目中尝试过,结果并不比 MVC 项目中的关注点分离差。有一些框架可以帮助你实现它,但出于某种原因我更喜欢自己实现它(毕竟它是几个基础 类 和一个基础接口)