How do I use a variable outside of a partial class? - c#

I'm new to C#, and I'm new to the idea of "partial" classes.
I wish to access the "grid" variable outside of this "MainWindow" class. How would I go about doing that?

Partial means that your class is split among different files, it has nothing to do with the exposure of variables to other classes.
Your grid is a local variable in your current method, so it's not accessible by others. If you want to make it accessible, define it as a property instead.
public DataGrid Grid { get; set; }

Even though it is technically possible, you should not make your data grid accessible outside the class. The grid is part of the view managed by your class, so making the grid accessible to other classes breaks encapsulation by making implementation details of your form visible.
I have another class, Server, and it receives data that I wish to add to grid.ItemSource.
Then your Server class should provide a data source to which your form should bind the grid. In other words, the access should go in the other direction.

You need to declare the variable as a public member of the class like this
public partial class MainWindow ...
{
public DataGrid grid;
public MainWindow()
{
...
}
public void DataGrid_Loaded(...)
{
...
grid = sender as DataGrid;
...
}
}
Now you can access to the variable in this way
var x = MainWindow.grid;

Related

Generic control to have inherit methods in WinForm

I have to work on a project on which there are several Form which have 80% of the code the same. So I try to create a generic class to make inheritate all my Forms of the UserControl class (the basic one) and my own class. But .Net doesn't support multi classs inheritance. So I create a middle class to do the inheritance chain like I can see on the net but I think I miss another step. Each class is in a different file for information.
The problem is I can't open anymore the designer for my initial Forms, because "Visual Studio cannot open a designer for the file because the class within it does not inherit from a class that can be visually designed".
Other information, I have a Mainwindow which inherite from "Form" and call one or another UserControl I design to show it.
What I had at the beginning :
namespace i2SIMDCProduction
{
public partial class MyForm1 : UserControl
{
public MyForm1(MyOwnClass myClass)
{
InitializeComponent();
this.myClass = myClass;
}
}
}
namespace i2SIMDCProduction
{
public partial class MyForm2 : UserControl
{
public MyForm2(MyOwnClass myClass)
{
InitializeComponent();
this.myClass = myClass;
}
}
}
What I have now :
namespace i2SIMDCProduction
{
public partial class MyForm1 : MyMiddleClass
{
public MyForm1(MyOwnClass myClass)
{
InitializeComponent();
this.myClass = myClass;
}
}
}
namespace i2SIMDCProduction
{
public partial class MyForm2 : MyMiddleClass
{
public MyForm2(MyOwnClass myClass)
{
InitializeComponent();
this.myClass = myClass;
}
}
}
namespace i2SIMDCProduction
{
public partial class MyMiddleClass : UserControl
{
public void MethodForAllChild()
{
}
}
}
Thank you in advance for any kind of help. I tried different things already (create a third class at the top of the file of my Forms for example, create empty constructor, ...) but nothing which works for now. The more frustrating is it is compiling and working but only the designer is KO.
If you want different forms to share the same visual controls on the screen then you set up inheritance between the forms.
Use the inherited form option in Visual Studio
For example, Form1 has a group box, with a label and two text boxes
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void CommonMethod()
{
}
}
and Form2 inherits from From1 and adds a list box
public partial class Form2 : Form1
{
public Form2()
{
InitializeComponent();
}
public void SpecificMethod()
{
base.CommonMethod();
}
}
As you can see the controls from Form1 show up on Form2 also with a little icon to indicate that they are inherited.
If instead you just need to share code (like business logic) and not visual controls, then you create a separate class to hold the code with a link to the parent form, and then each form should contain an instance of this class.
What you want to do is a Model-View-Controler setup, where the Model is only data-related classes, View is only UI code, and the controller goes between the two doing the heavy lifting with processing user inputs and updating values.
The inheritance and designer in Windows Forms is a problem.
I have a Form with an splitter, two listboxes and some other controls. That form is used to translate (map) some items. You select one item at left, one at right and click button to match. They are the same item in different providers.
I have another provider that require some extra controls to do the translation. May be 90% or more of the code is the same, but I need some extra for this provider.
The options that I saw:
Add these extra controls (protected or public) to the Form, hidden by default and without use. In Form derived class, you use them. You haven't the designer in derived Form, but you don't need because controls are in base Form. The problem with this approach is that the designer part of inheritance of derived Form is in base Form. It's a nonsense. I don't recomend this option.
Don't use the designer in derived Form. Starting in the previous point, copy the designer code added for your derived Form into your derived Form and leave your base Form as at first stage, without nothing of derived Form. You don't use the designer but you can use it temporary, copy/paste and have a good inheritance... without the designer in derived Form. It's a good option if your derived Forms has few changes, few maintenance in the designer part.
You can "Add" some logic to your base Form to allow extensions. For example, below of the ListBox, I can add a Panel (hidden by default) and some methods like ShowLeftPanel/ShowRightPanel. By default, these panels aren't used, but in derived class I can add an UserControl in left panel and show it. And that UserControl show the properties that I need to show in the special provider. Add some virtual methods for listbox selection changed, to update the UserControl. In this way, your UserControl has designer and also the base Form. You only need add some "extension points" in your form (a Panel, a Splitter...) and give some methods to interact with this parts of the base Form. And this is ok with inheritance because is something generic, like Tag property in controls.
UPDATE
Check this solution and tell me about it. Make your Forms like this:
public partial class MyForm1 : UserControl, IMyUserControl
{
private readonly MyOwnClass myClass;
public MyForm1(MyOwnClass myClass, MyMiddleClass myMiddle)
{
InitializeComponent();
this.myClass = myClass;
this.MyMiddle = myMiddle;
}
public MyMiddleClass MyMiddle { get; }
}
In this way, all your panel's forms are IMyUserControl:
public class MyUserControl : IMyUserControl
{
public MyMiddleClass MyMiddle { get; }
}
So, having any of your panel's form, you can cast to IMyUserControl and get the related MyMiddleClass having access to methods like MethodForAllChild:
public class MyMiddleClass
{
public void MethodForAllChild()
{
}
}
In your main form, you may have some property or method that give you access to your UserControl. Create a method that give you the middle instance of the current UserControl:
private MyMiddleClass GetMyMiddle()
{
UserControl userControl = GetYourMainFormCurrentUserControl();
IMyUserControl myUserControl = userControl as IMyUserControl;
return myUserControl?.MyMiddle;
}
And use it in your main form when you need:
MyMiddleClass myMiddle = GetMyMiddle();
if (myMiddle != null)
{
myMiddle.MethodForAllChild();
}
In this way, you only need implement the interface and add a property in your forms/usercontrols. In the main form you can get this middleclass and the code to reuse is only in that class and shared in all places. You don't need copy/paste if you add or change something in the middle class.
UPDATE 2
I'm going to explain in other form how it works because the code is written above. The goal is having the code only in one place, without duplicate it.
You define an interface in a very similar way as a class but without implementation (this is not really true in lastest C# versions but we can suppose that is without code). C# don't allow multiple inheritance but you can derive from a class and implement as many interfaces as you want.
When we define IMyUserControl we are telling that every class that implements IMyUserControl, has a property MyMiddle. When MyForm1 implements IMyUserControl, if you don't add the MyMiddle property, you get a compiler error. The key with this solution is that add and implement this interface in each form is very easy: add IMyUserControl, the property and a parameter in the constructor to set the property.
So, all your forms implements now IMyUserControl. I don't know where are your forms but it's sure that you have a way to get access to your UserControl. Maybe a variable or an array in which you add your user controls. You are working with them, so you can access to your user controls. Well, if you have an UserControl instance, and you know that your UserControl implements IMyUserControl, you can cast your UserControl to IMyUserControl and after the cast, you have access to the interface, in this case, to the MyMiddle property.
And we put in MyMiddle all the code that you want to share.
If you add some code of your main form, where you work with your forms, I can help you with the code. I haven't more code than existing in my answer.

C# and WPF: controls inaccessible from another class

I just started fiddling around with C# and WPF.
Let's say that I want to instantiate a Black grid and that I want to randomly move around a red square in said Grid.
Currently I can basically do whatever I want as long as I keep everything in "MainWindow.xaml.cs"...
Now, my problem is that if I create a new class (e.g., "MakeStuffHappen.cs") and from it I try to access the Grid (named "MyGrid") that will be instantiated by MainWindow's constructor, intellisense doesn't "see" it.
I tried making a getter that returns "MyGrid" but then the compiler says that "an object reference is required for the non-static field, method, or property 'ProjectName.MainWindow.getGrid()'.
Obviously I cannot define MainWindow as a static class...
Any tips on how to solve this?
Thanks!
P.S. Since I'm evidently no programmer I'm not necessarily aware of the technical terms to use when looking up information... so I apologize in advance if this question has been already asked.
P.P.S. I saw this: Access MainWIndow Control from a class in a separate file but it doesn't help.
Once your view is initialized (when the OnInitialized event fires) you can pass the initialized Grid into your helper class:
MainWindow.xaml.cs:
public partial class MainWindow
{
MakeStuffHappen helper = null;
public MainWindow()
{
OnInitialized += (s,e)=> { helper = new MakeStuffHappen(this.MyGridName); }
}
}
MakeStuffHappen.cs
public class MakeStuffHappen
{
Grid theGrid = null;
public MakeStuffHappen(Grid grid)
{
theGrid = grid;
// Do stuff with the grid.
}
}

How to create a 'style master' winforms control

I have an application with several DataGridView controls. I would like to create a master control or component (I'm not sure which one to use) where I can define basic coloring and behavior. However, since all DataGridView controls have different columns in the application I want to define columns after placing a new instance on the form and not in the master form.
Can you suggest a way to do this? Thanks in advance.
Have something like your own MasterGridView where you define all common behavior, colour, etc.. & then inherit all respective datagridviews from this one.
public class MasterDataGridView: System.Windows.Forms.DataGridView
{
public MasterDataGridView()
{
BackColor = Color.Yellow;
// define other behaviours
}
}
public class OrdersDataGridView : MasterDataGridView
{
// data binding, column addition etc can be handle in respective grid views
}
public class ReportsDataGridView : MasterDataGridView
{
}
...
etc.

Inheriting from a System.Web.UI.UserControl base class

First off, I am wondering if this is possible. I read slight grumblings around the internet about this, but I was not entirely sure.
My scenario: I have a base chart class which has some methods which all charts should have.
public partial class BaseChart : System.Web.UI.UserControl
{
public BaseChart()
{
}
public void ToggleLegend()
{
Chart1.Legends[0].Enabled = !Chart1.Legends[0].Enabled;
}
}
There is also some mark-up for this BaseChart -- setting background colors, etc. All charts which inherit BaseChart should use this starting mark-up and be able to build upon it.
I would then like to do this:
public partial class HistoricalLineChart : BaseChart
{
public HistoricalLineChart()
: base()
{
}
public HistoricalLineChart(int reportID)
: base()
{
Chart1.Titles[0].Text = "Hello World";
}
}
where HistoricalLineChart is a web user control with no mark-up e.g. "HistoricalLineChart.ascx"
The problem is that Chart1 is undefined when in HistoricalLineChart's scope. Is there something that I am missing here?
Thanks.
Though usually one ends up just making a custom control in this situation (as the other answer suggest), and this is good for many reasons, there are a couple other approaches that may be useful in situations where complicated markup makes a server control infeasible.
1) Create a base class that has all the functionality common to your implementations and inherits UserControl. If you really want to include markup as part of the base class, you could put it in a separate usercontrol with no code, and load it from the abstract class, though this seems a little ugly. If the markup that is shared is simple, though, just render it from code instead.
public abstract class MyUserControl: UserControl
{
public Chart Chart1;
public void ToggleLegend()
{
Chart1.Legends[0].Enabled = !Chart1.Legends[0].Enabled;
}
public override void CreateChildControls()
{
Controls.Add(Page.LoadControl("path/to/mymarkup/control"));
// or add them in code
BuildBaseControls();
}
}
2) Create UserControl implementations that inherit MyUserControl instead of UserControl, and add the markup
public partial class HistoricalLineChart : MyUserControl
{
public HistoricalLineChart(int reportID)
: base()
{
Chart1.Titles[0].Text = "Hello World";
}
}
You could also create an interface that describes any controls that should appear in the markup and implement that. This is nice because it gives you a construct that is applicable to either a UserControl (where the controls are defined in markup) or a WebControl (where the controls are created in code), leaving the actual details of the markup to each implementation, but letting you share the functionality.
Unfortunately the markup portion of BaseChart is not actually part of the BaseChart class. The markup is part of a class that gets created when you compile and it inherits from BaseChart. So HistoricalLineChart only contains what you've explicitly set in BaseChart and none of the markup. The only way I know to work around this is to use a Composite Control or Custom Server Control (vs a UserControl).It's a bit more of a pain since you have to add your child controls programmatically, but should do what you want.
Here is an example: http://msdn.microsoft.com/en-us/library/3257x3ea(v=VS.100).aspx
Basically:
Inherit from CompositeControl.
Override CreateChildControls. In this method, you can add all of your child controls (like your chart).
Optional: Override Render. Override this if you need custom markup in addition to the child controls. You can output your custom markup plus call RenderControl on all of your child controls to tell them where to render their output. If you don't override this method at all, then the composite control will render out the child controls in the order that they are in the controls collection.
Here are a couple more tutorials:
http://www.codeproject.com/KB/custom-controls/customdialog.aspx
http://msdn.microsoft.com/en-us/library/aa479016.aspx
http://www.codersource.net/asp-net/asp-net-advanced/creating-a-composite-control-in-asp-net.aspx
You can make a protected property in BaseChart that exposes the chart.

Settings properties of a child in a composite control in an .aspx page

I've got a composite control (class) that exposes an asp:Label through a get-property. Is is possible to set the Text property of the Label through aspx-code?
I'd like to do something like this:
<cfw:MyCompositeControl runat="server" Label.Text="Test" />
One solution is adding each property to the composite class (like a public LabelText), but I'd like to set any property of any child control. So as new features of child controls become available, I'd like to be able to use them on my composite control. So basically I would like to set any property of the exposed child control.
You could do it with inner properties:
[ParseChildren(ChildrenAsProperties = true)]
public partial class MyControl: UserControl
{
[PersistenceMode(PersistenceMode.InnerProperty)]
public TestClass TestLabel
{
get;set;
}
}
public class TestClass
{
public string Field1
{ get; set; }
public string Field2
{ get; set; }
}
Markup:
<MyTag:MyControl runat="server">
<TestLabel Field1="a" Field2="b" />
</MyTag:MyControl>
I've never actually done this with a simple property before - usually, you are using collections. In playing with this example on my own, in the markup window, Visual Studio will allow you to create more than one instance of TestLabel inside <MyTag:MyControl> - that is, it doesn't seem to care that it's a simple property rather than a collection, I suspect if you put in more than one entry just the last one would result.
FYI... if you haven't done this before, prepare to be annoyed by intellisense. It can be annoyingly obtuse about updating the behavior after you make changes to a class, you will need to recompile and probably wait for some arbitrary amount of time before it acts the way it's supposed to.
You need to expose it as a property in the composite control's class:-
public string LabelText
{
get
{
return Label.Text;
}
set
{
Label.Text = value;
}
}
Then you can control it from the server tag like:-
<cfw:MyCompositeControl runat="server" LabelText="Test" />
You should expose a public property that returns/sets the Text property of the Label.
MSDN
Edit:
Your idea to access all child controls of the composite control from the page is not recommended:
One approach would be to access the child controls via MyCompositeControl.FindControl(ID) (or extension methods) what would be very static and error-prone if you want to remove controls or change the IDs.
Another approach would be to make the child controls public but that is also bad design because it opens the door for misusing your control and would be also problematic if you want to change the childcontrols and pages are already accessing them directly.

Categories