I have an application that can display items in two different ways, in rows using a StackPanel or icons using a WrapPanel. Which way it displays these items depends on a config setting. To populate these panels I have two seperate classes one inherits from the WrapPanel the other from the StackPanel. I was able to cut down on duplicated code using an Inferface. However I still had a lot of duplicated code the only difference between the code is the references to StackPanel or WrapPanel.
What I would really like to do is create a class that inherits from either the StackPanel or WrapPanel depending on the config setting.
public class ContainerBase : <wrap or stack>
{
//Do stuff!
}
Is this possible? Am I approaching this incorrectly?
When I said "composition but not inheritance" in first comment, I meant smth like the following:
public class PanelPresentatinLogic
{
public Panel Panel{get;set;}
public void DoSomeDuplicatingStuff()
{
//Do stuff! with Panel
}
}
public class SortOfStackPanel : StackPanel
{
private readonly PanelPresentatinLogic _panelPresentatinLogic;
public SortOfStackPanel(PanelPresentatinLogic presentationLogic)
{
_panelPresentatinLogic = presentationLogic;
_panelPresentatinLogic.Panel = this;
}
public void DoSomeDuplicatingStuff()
{
_panelPresentatinLogic.DoSomeDuplicatingStuff();
}
}
public class SortOfWrapPanel : WrapPanel
{
private readonly PanelPresentatinLogic _panelPresentatinLogic;
public SortOfWrapPanel(PanelPresentatinLogic presentationLogic)
{
_panelPresentatinLogic = presentationLogic;
_panelPresentatinLogic.Panel = this;
}
public void DoSomeDuplicatingStuff()
{
_panelPresentatinLogic.DoSomeDuplicatingStuff();
}
}
public class UsageSample
{
public void PopulateCollectionOfItemsDependingOnConfigHopeYouveGotTheIdea()
{
string configValue = configuration["PanelKind"];
PanelPresentatinLogic panelPresentatinLogic = new PanelPresentatinLogic();
Panel panel = configValue == "Wrap"
? new SortOfWrapPanel(panelPresentatinLogic)
: new SortOfStackPanel(panelPresentatinLogic);
// TODO: add panel to GUI
}
}
You can use Generics for this;
public class ContainerBase<T> where T : Panel
You can then use the config setting to initialize the right type.
In WPF you are intended to not use controls to populate itself. Instead, use MVVM pattern.
You can achieve your goal with only one class providing the data (tipically an ObservableCollection) and loading that "view mode variable" into a property at MVVM.
Then you can use a an ItemsPanel with an DataTemplateSelector to select the view.
May be you can use Panel?
public class ContainerBase : <wrap or stack>
{
//Do stuff!
}
Related
I currently have a simple WPF application, in the MainWindow I will have a variable (In this case the variable is a class that holds data). Then I have a User Control which has the same variable.
Currently, I'm passing the variable with the ref keyword and it works perfectly fine, however, is this save/good practice? Is there a better way of linking this two variables together?
I am aware of the existence of DependencyProperty, however, I could not get it to work.
MainWindow:
public partial class MainWindow : Window
{
private TestClassWithInfo m_SelectedInfo;
public MainWindow()
{
InitializeComponent();
m_SelectedInfo = new DrawingInformation();
TestGridUC mp = new TestGridUC(ref m_SelectedInfo);
TestCanvas.Childrens.Add(mp);
}
}
TestGridUI:
public partial class TestGridUC : UserControl {
private TestClassWithInfo m_SelectedInfo;
public TestGridUC (ref TestClassWithInfo e)
{
InitializeComponent();
m_SelectedInfo = e;
}
}
TestClassWithInfo:
public class TestClassWithInfo
{
public Image imageTest;
public int intTest;
public TestClassWithInfo ()
{
m_img = null;
m_layer = 0;
}
}
I am aware of the existence of DependencyProperty, however, I could not get it to work.
A dependency property really is the way to go about it though:
public partial class TestGridUC : UserControl
{
public TestGridUC()
{
InitializeComponent();
}
public TestClassWithInfo Info
{
get { return (TestClassWithInfo)GetValue(InfoProperty); }
set { SetValue(InfoProperty, value); }
}
public static readonly DependencyProperty InfoProperty =
DependencyProperty.Register("Info", typeof(TestClassWithInfo), typeof(TestGridUC),
new PropertyMetadata(null /*or initialize to a default of new TestClassWithInfo()*/ ));
}
Now you can bind to that property from the xaml in your MainWindow:
<local:TestGridUC
Info="{Binding Info}"></local:TestGridUC>
If you need help with that part, as pr177 answered there are many tutorials on getting started with WPF with the MVVM pattern. The basics here would involve a view model object that contains a TestClassWithInfo public property that you bind to.
Have a look at the MVVM (Model-View-ViewModel) Pattern
There are many tutorials & introductions like that:
https://blogs.msdn.microsoft.com/ivo_manolov/2012/03/17/model-view-viewmodel-mvvm-applications-general-introduction/
or
https://social.technet.microsoft.com/wiki/contents/articles/32164.wpf-mvvm-step-by-step-2.aspx
How i can hide my user control from designer form, to show in bottom of designer, like timers or openFileDialog...
What i want to do is a custom menuStrip, with animation, progressBar, dateTimePicker, and so on. But i don't want to be visible in designer, just like normal menuStrip.
I tried to make my user control as component, but if i do it, i lose others.
An example would be :
public class ExampleForm : Form
{
public ExampleForm()
{
CustomMenuStrip a = new CustomMenuStrip();
a.Items.Add(new CustomMenuStripItem()
{
///Stuff
});
}
}
public class CustomMenuStrip : UserControl
{
public List<CustmMenuStripItem> Items;
public CustomMenuStrip()
{
//Do Stuff
}
}
public class CustomMenuStripItem : UserControl
{
public CustomMenuStripItem()
{
//Do Stuff
}
}
Any ideas?
Thank's in advance.
Andrei
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 several UserControls that are sharing some common properties. Example:
private List<MyObject> Sample
{
get
{
return Session["MyObject"] as List<MyObject>;
}
set
{
Session["MyObject"] = value;
}
}
I want to share this to all user controls inside my project. (Not to other projects in a solution, of course). What I'm trying to do is create a separate class and inherit from that class. Something like:
public class SampleBase : Web.UI.UserControl
{
protected List<MyObject> Sample
{
get
{
return Session["MyObject"] as List<MyObject>;
}
set
{
Session["MyObject"] = value;
}
}
}
And then my control can inherit those values by deriving from that class:
partial class myControl : SampleBase
One problem I encounter is that I cannot derive from base if control already has something inherited:
partial class myControl : SomethingELSE
Otherwise it works fine, but I'm not sure if it is a good approach and I'm looking for suggestions.
If my understanding is correct, you only want to get rid of the inheritance hierarchy of your User Controls
Another approach would be using Extension Methods
For example:
Interface to mark your USerControls
public interface IMyUserControlMark { }
Extensions
public static class MyUserClassExtensions
{
public static List<object> GetSampleData(this IMyUserControlMark myUserControl)
{
if (HttpContext.Current.Session["MyObject"] == null)
{
return Enumerable.Empty<object>().ToList();
}
return HttpContext.Current.Session["MyObject"] as List<object>;
}
public static void SetSampleData(this IMyUserControlMark myUserControl, List<object> myObject)
{
HttpContext.Current.Session["MyObject"] = myObject;
}
}
User control
public partial class Content1 : System.Web.UI.UserControl, IMyUserControlMark
{
...
}
public partial class Content2 : System.Web.UI.UserControl, IMyUserControlMark
{
....
}
Now you will be able to call your extension methods from within your UserControl or from the ASPX code behind like this:
From the UserControl
var myObject = this.GetSampleData();
this.SetSampleData(myObject);
From the ASPX code behind
var myObject = this.uc1.GetSampleData();
this.uc1.SetSampleData(myObject);
This is a classic example where you need to "favor composition over inheritance".
Instead of inheriting from the class, you hold a reference to an instance of the class. Then you provide simple pass-through code to access the methods/properties of the class.
So, for your example:
public class SomeBehavior
{
public List<MyObject> Sample
{
get { return Session["MyObject"] as List<MyObject>; }
set { Session["MyObject"] = value; }
}
}
public class MyControl : UserControl
{
private SomeBehavior _someBehavior;
public MyControl()
{
_someBehavior = new SomeBehavior();
}
public List<MyObject> Sample
{
get { return _someBehavior.Sample; }
set { _someBehavior.Sample = value; }
}
}
Another option is to allow access to the behavior class directly:
public class MyControl : UserControl
{
public SomeBehavior SomeBehavior { get; private set; }
public MyControl()
{
SomeBehavior = new SomeBehavior();
}
}
The advantage of this is that you don't have to write the pass-through code. The disadvantage is that it violates the Law of Demeter, which says that you should "only talk to your immediate friends". If you do it this way, other classes that use MyControl need to know about SomeBehavior. Following the Law Of Demeter can improve maintainability and adaptability of your code, but it comes at a cost of lots of pass-through code.
Apart from previous solutions, maybe it's time for applying some MVC/MVP pattern?
For web forms there is a great framework called WebFormsMVP: link
In the library there is a mechanism called Cross Presenter Messaging thanks to which you can share a data between your controls using the publish/subscribe pattern.
For better explanation look here and here
I suggest to give the library a chance :)
In C# you can inherit from only one class and implement multiple interfaces.
This is allowed:
partial class myControl : SampleBase
partial class myControl : SampleBase, Interface1
partial class myControl : SampleBase, Interface1, Interface2, Interface3
This is NOT allowed:
partial class myControl : SomethingELSE, SampleBase
Try making SomethingELSE inherit from SampleBase if it satisfies your design. If not, then I suggest encapsulating SampleBase as a property of each control that needs it as it also suggested #DanM.
I need to add shared functionality to both Forms and UserControls. Since multiple inheritance isn't supported in .net I wonder how I best tackle this?
The shared functionality is a dictionary that is filled by the form or usercontrol and then processed.
Regards
public class SharedFunctionality
{
public void ImportantToCallThisOnLoad();
}
public class MyForm : Form
{
SharedFunctionality mySharedFunctionality = new SharedFunctionality();
public void OnLoad()
{
mySharedFunctionality.ImportantToCallThisOnLoad();
}
}
public class MyControl : Control
{
SharedFunctionality mySharedFunctionality = new SharedFunctionality();
public void OnLoad()
{
mySharedFunctionality.ImportantToCallThisOnLoad();
}
}
Instead of having the Forms & UserControls inherit from a base class can you encapsulate the logic inside of a self contained object so that each form will new up? Then you can limit in the base class just the instantion and interaction with this object which hopefuly is minimal so having it done twice isn't a big deal.