I have a main window in WPF and it contains:
A Tab Control having different tabs. Each tab has a different control in it and contains a data grid.
A frame control - it also has different controls respectively for data entry.
A Refresh Button (Yet to implement)
I have implemented the tab controls and frame for data entry successfully but problem is I cannot refresh the tab control until I switch across the tabs. I want to have a central Refresh button on main-window (one I aforementioned).
Can anyone guide me how can I do it?
And since tab's current object type will only be decided at the Run-time, so is it Polymorphism?
You can use an interface for all the usercontrols:
public interface IRefreshAble
{
void Refresh();
}
public interface ICanDeleteItem
{
void Delete(/*parameters omitted*/);
bool CanDelete { get; }
}
public interface IHoldATypedItem ///sorry for bad name
{
Type TheType { get; }
}
Then you implement this interface by the usercontrols:
public class TheUserControl : UserControl, IRefreshAble, ICanDeleteItem, IHoldATypedItem
{
public void Refresh()
{
//Your refreshcode
}
public bool CanDelete {get { /*code that indicates if an item can be deleted*/ } }
public void Delete(/*parameters ommited*/)
{
if(CanDelete)
{
//Delete Item
}
}
public Type TheType { get { return typeOf(Employee); } }
// otherstuff
}
Now you can put all of your UserControls(for example) in a List<IRefreshAble> and do stuff like:
foreach(IRefreshAble item in theList)
{
item.Refresh();
}
If you have more than this Refresh() method common for all Usercontrols you can just expand the interface for this members and get the polymorphism you need.
Related
I'm extending my own custom control, which extends the UserControl class.
I can see all the elements fine in the extending class' designer, but all the properties of the extended custom control appear disabled and when selecting its element with the mouse a "locked" icon appears.
How can I fix that? I would like to be able to modify these properties from the designer.
EDIT: Definition of the custom control, which extends from UserControl.
namespace Wizard
{
[Designer(typeof(Wizard.StepDesigner))]
[DefaultProperty("TitlePanel, NavigationPanel")]
public partial class Step : UserControl
{
public Step()
{
InitializeComponent();
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public Title TitlePanel
{
get
{
return this.title1;
}
set
{
this.title1 = value;
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public Panel ContentPanel
{
get
{
return this.contentPanel;
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public Navigation NavigationPanel
{
get
{
return this.navigation1;
}
}
}
internal class StepDesigner : ParentControlDesigner
{
public override void Initialize(System.ComponentModel.IComponent component)
{
base.Initialize(component);
if (this.Control is Step)
{
Step control = (Step)this.Control;
this.EnableDesignMode(control.TitlePanel, "TitlePanel");
this.EnableDesignMode(control.ContentPanel, "ContentPanel");
this.EnableDesignMode(control.NavigationPanel, "NavigationPanel");
}
}
}
}
As I already pointed out in the comments, the modifiers of the properties were all set to private and changing them to protected and rebuilding the solution fixed the "problem".
I have a main object which has some properties and methods. This object can have multiple parts. These parts are required. The amount of these parts is variable.
Each part has different properties and is referenced to the main object.
To accomplish this in my GUI I have a tabcontrol. The first tab is the main object. The other tabs describes the main object further. These 'other' tabs are the parts I mentioned above.
I am trying to design an architecture, but I can't figure I hope yoy can help me.
As suggested from the answers, the part-tabs inherit from an interface. But how does the main know about it's parts? The parts can't be hardcoded because it is variable. To hardcode the parts is a violation of the OCP principle.
Also, when loading the main object, again, how does it knows about it parts? I have to 'register' them somewhere, but where?
Create interface for your parts, that can have reference to main object. And main object will contain collection of parts as Collection<IPart>
class MainObject
{
Collection<IPart> Parts {get;set;}
}
interface IPart
{
MainObject MainObject {get;set;}
}
class SomePartImpl : IPart
{
//properties of this IPart implementation
}
This classes is entities. Your data service must implement logic for saving and cascade operations.
Sample wcf service(from my project):
[EnableClientAccess]
public class ModelService : LinqToEntitiesDomainService<dpirtEntities>
{
public void InsertZone(Zone zone)
{
if ((zone.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(zone, EntityState.Added);
}
else
{
this.ObjectContext.Zones.AddObject(zone);
}
}
public void UpdateZone(Zone currentZone)
{
Zone originalZone = this.ChangeSet.GetOriginal(currentZone);
if ((currentZone.EntityState == EntityState.Detached))
{
if (originalZone != null)
{
this.ObjectContext.Zones.AttachAsModified(currentZone, originalZone);
}
else
{
this.ObjectContext.Zones.Attach(currentZone);
}
}
foreach (Document doc in this.ChangeSet.GetAssociatedChanges(currentZone, o => o.Documents))
{
ChangeOperation op = this.ChangeSet.GetChangeOperation(doc);
switch (op)
{
case ChangeOperation.Insert:
if ((doc.EntityState != EntityState.Added))
{
if ((doc.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(doc, EntityState.Added);
}
else
{
this.ObjectContext.AddToDocuments(doc);
}
}
break;
case ChangeOperation.Update:
this.ObjectContext.Documents.AttachAsModified(doc, this.ChangeSet.GetOriginal(doc));
break;
case ChangeOperation.Delete:
if (doc.EntityState == EntityState.Detached)
{
this.ObjectContext.Attach(doc);
}
this.ObjectContext.DeleteObject(doc);
break;
case ChangeOperation.None:
break;
default:
break;
}
}
}
public void DeleteZone(Zone zone)
{
if ((zone.EntityState == EntityState.Detached))
{
this.ObjectContext.Zones.Attach(zone);
}
this.ObjectContext.Zones.DeleteObject(zone);
}
}
Have a List or Dictionary in your Main class and store the references to the different objects.
For example:
All the tabs implement an interface called IScreenTab.
class MainTab : IScreenTab
{
// Store a map of scree name to screen object
// You can also just use a List<IScreenTab>
private Dictionary<string, IScreenTab> m_OtherScreens;
// Your implementation goes here
public MainTab(){ }
public MainTab(List<IScreenTab> screenTabList){ }
public AddTab(string screenName, IScreenTab screenTabObj){ }
}
I've done something similar in the past, and I decoupled my GUI from my domain design by using an IoC container. In my code I used StructureMap, which was very easy to adopt.
I had exactly the same setup in which there was an 'editor' which contained a number of 'tabs'. Each tab could either contain some different view of my 'object' or it could show an item from collections stored within the 'object'. So there were a number of static and variable tabs.
So, I needed two things.
1. A way to create an editor, with the correct number of tabs.
2. A way to create the tab, plus all it's controls.
So, I created an interface for each, which looked loosely like this.
public interface IEditorFactory<TObject>
{
Editor CreateEditor(TObject instance);
}
public interface ITabEditorFactory<TObject>
{
void CreateTab(TObject instance, Editor parent);
}
I'll leave Editor up to your imagination. By in my app it was a custom UserControl, with various features and behaviour.
Next, imagine we had a Person, who had personal info, an Address an multiple contracts.
public class Person
{
public string Title { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public string EmployeeNumber { get; set; }
public string NationalInsuranceNumber { get; set; }
public Address Address { get; set; }
public IEnumerable<Contract> Contracts { get; }
}
My app wanted to display one 'Personal Details' tab, one 'Employment' tab, one 'Address' tab and multiple 'Contract' tabs.
I implemented the following.
public class PersonalTab : ITabEditorFactory { ... }
public class EmployeeTab : ITabEditorFactory { ... }
public class AddressTab : ITabEditorFactory { ... }
public class ContractTab : ITabEditorFactory { ... }
Notice how #1 and #2 implement the same ITabEditorFactory. That's because they both display different aspects of the Person.
But before I had implemented those I implemented the PersonEditor
public class PersonEditor : IEditorFactory { ... }
It was good that I implemented this first, as it forced de-coupling my editor factory from all the tab factories. I wouldn't accidentally slip in any references to concrete classes. My editor factory just knew how to ask for a ITabEditorFactory<> for the Person, Address and Contract classes.
My final solution was a little more complicated than I outlined above, as it also covered Editor re-use for different instances, how to handle multiple (or no) tab editors for any a single class, and being able to define security on a tab-by-tab basis.
The end result was that I had a GUI model that was decoupled from my domain, and was extensible without requiring me to change a single line of existing code.
Lovely jubbly.
I want to implement access control for usercontrols depending on user role(s), I want to do it on the control base class, in such way that on every user control I only need to set a string with allowed roles to see the user control
This is how an user control class may look like:
public partial class SimpleMenu : MyUsrControlBase
{
protected void Page_Load(object sender, EventArgs e)
{
AlloweRoles = "RoleA, RoleB"
//specific user control functionality
}
}
The base class:
public abstract class MyUsrControlBase : UserControl
{
private string _allowedRoles;
protected internal string AllowedRoles
{
set
{
_allowedRoles = value;
ValidateRoles();
}
}
private ValidateRoles()
{
//Role validation logic
if (RoleHasAccess)
{
// Set user control visibility to true
}
else
{
// Set user control visibility to false
}
}
}
How to set up user control visibility from the base class depending on the validation result?
Also which event in the user control is the best to set the roles?
AlloweRoles = "RoleA, RoleB"
You can set the inherited Visible property from the base class:
private void ValidateRoles()
{
// Role validation logic.
Visible = RoleHasAccess;
}
EDIT: Concerning your second question, you can initialize the AllowedRoles property in the derived class' constructor, so it will be set for the whole lifespan of the user control:
public partial class SimpleMenu : MyUserControlBase
{
public SimpleMenu()
{
AllowedRoles = "RoleA, RoleB";
}
}
How can I call aspx content page methods from usercontrol?
Probably the cleanest solution is to extract an interface containing the methods that must be called from the UserControl, and then pass the interface from the page to the control, e.g:
public interface ISomeService
{
void Method1();
bool Method2();
}
public class MyContentPage : Page, ISomeService
{
void Method1() { ... }
bool Method2() { ... }
override OnLoad(...)
{
TheUserControl.SetService(this as ISomeService);
}
}
public class MyUserControl : UserControl
{
public void SetService(ISomeService service)
{
_service = service;
}
private void SomeOtherMethod()
{
_service.Method1();
}
}
Another variation would be to simply require the page containing the user control to implement the required interface. This makes the SetService() method unneeded:
public class MyUserControl : UserControl
{
private void SomeOtherMethod()
{
// page must implement ISomeService, throws an exception otherwise
(Page as ISomeService).Method1();
}
}
You are most likely creating a very bad design at this point. If it needs to have access to its parent, it probably shouldn't be a UserControl. Are you sure you can't just add an event handler to your usercontrol that the parent page calls on certain events?
That said, your UserControl will have the .Page property you can cast to get your parent page. Again, it's probably a very bad idea and you should revisit your design.
Here is the design problem in pseudo example:
It is ASP.NET User control (UC) which uses the "Food" object as data source and this object has property FoodType - "Veg" || "Nonveg".
The user control changes UI display depending upon FoodType property. In code-behind class of User Control, some methods have same if/then/else condition: if(Food.FoodType == "Veg")... else ...
Here, I would like use State-like pattern such that code-behind class of User Control will contain two inner/nested classes, i.e. "VegFood" class and "NonvegFood" class. Now, lets say, NonvegFood class will contain its own logic implementation.
But having one interface, two instance classes (as nested) which will be used in this user control only, could be overdesign. In addition to that, UC does not have driver method where I can call related methods in one if block, like they are "DataBound" and "ItemCreated".
Still, is it possible to have State like pattern inside UC class? Probably two instance inner classes inside UC and somehow if I can delegate call to one of these inner class?
class UC : UserControl
{
class VegFood
{
string DisplayName
{
get
{
return "Rice";
}
}
}
class NonvegFood
{
string DisplayName
{
get
{
return "Chicken";
}
}
}
protected string DisplayName
{
get
{
return Instance.DisplayName;
}
}
/*********** MAGIC Property ****************/
private ? Instance
{
get
{
return ?;
}
}
}
I do not think that having three nested classes is not design overkill if it makes the code easier to maintain.
I would suggest an abstract base State class which defines the contract of your states. Each state would inherit from this.
Extended your code sample:
class UC : UserControl
{
protected string DisplayName
{
get
{
return Instance.DisplayName;
}
}
/*********** MAGIC Property ****************/
private FoodState _instance = null;
private FoodState Instance
{
get
{
if (_instance == null)
{
if (FoodType == "Veg")
{
_instance = new VegFood();
}
else
{
_instance = new NonvegFood();
}
}
return _instance;
}
}
abstract class FoodState
{
abstract public string DisplayName {get;}
}
class VegFood : FoodState
{
public string DisplayName
{
get
{
return "Rice";
}
}
}
class NonvegFood : FoodState
{
public string DisplayName
{
get
{
return "Chicken";
}
}
}
}
You probably don't need the protected DisplayName property on the UserControl directly, as Instance.DisplayName could be used directly by the aspx page.