Reputation: 9830
I have a situation where I need to have two totally different layouts for a Web User Control but it's quite important that the codebehind for the controls remains identical.
Is there any way I can use the same codebehind for two different Web User Controls? I've tried changing the Page directive to use the same class, but occasionally when you build, a .designer.cs
file gets generated with duplicate controls so you get a compilation error.
I also tried inheriting from a common base class but you cannot see any of the controls from this class, which makes it very difficult to take this approach.
Or is there a way to prevent the designer.cs class from being regenerated for the "clone" control?
Upvotes: 2
Views: 2105
Reputation: 23591
In addition to @Ondrej Svejdar 's correct answer I suggest that you take a look at the MVP design pattern and maybe use it with your Web Forms code. It works, I have tried it in a big project and the result is no worse than the separation of concerns in an MVC project. There are frameworks to help you implement it but for some reason I prefer implementing it myself (after all it is a couple of base classes and a base interface)
Upvotes: 1
Reputation: 2553
I have just now tested this in VS 2012.
.ascx.cs
and .ascx.Designer.cs
file from second controlPage
directive of second control for CodeBehind
and Inherits
attribute. No need to generate Designer file for second control.And it works. I don't know this is valid approach or not.
I have tested it by adding a Label
in each control and setting its value in code behind. The value reflects in both controls.
You may face issue when you have a asp.net control in one user control and it doesn't exists in other.
Upvotes: 2
Reputation: 22094
Create base class, and implement common logic there. Then inherit controls from this base class. For accessing controls from base class level make abstract get properties on base class level for every single control you'll need. Implement those properties in child control 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; }
}
}
Alternatively and a lot less elegant is locating controls at runtime; because you pay for searching the whole control tree and you have to handle control not found scenarios:
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";
}
}
Upvotes: 3