In my C# (3.5) solution, i have 2 projects- a Class Library and WinForm project.
All business logic are in class library. while adding/updating data from WinForm, if Class Library finds any error, it will raise error and set focus to associate control in WinForm.
Is it possible?
Thanks,
SKPaul.
All UI logic should remain in your WinForm project. You will have to pass your control to class library to set focus from the library which is mostly a bad design. Instead:
namespace ClassLibrary
{
public class Utility
{
public static string ReadData()
{
return "abc";
}
}
}
namespace Win_App
{
public partial class Form1 : Form
{
private void button2_Click(object sender, EventArgs e)
{
if (ClassLibrary.Utility.ReadData() == null)
{
MessageBox.Show("error, redo");
button2.Focus(); //you should handle this here.
return;
}
}
}
}
The basic idea here is to signal an appropriate return value in case of an error. For instance a null value for an object, or a false for a bool value. You should check that in UI project, and handle it there. In your case setting focus hence should be from WinForm project.
Related
Basically I have 2 projects, a form and a user control.
I need both of them to be in different projects but the form need to refer to the user control as it is using the user control. And the user control will need to refer to the form as it is using one of the form class. When I add the second one because it need the , VS will complain circular dependency which is understandable. How do I solve this?
Logically the form should depend on the user control. You could create an interface to replace the form within the user control project, and then have the form implement that interface.
Example user control project;
public interface IForm
{
string MyString { get; }
}
public class MyUserControl : UserControl
{
public IForm Form { get; set; }
private void ShowMyString()
{
String myString = Form.MyString;
...
}
}
Example Form project
public class MyForm : Form, IForm
{
public MYString { get "My String Value"; }
}
I think the root cause of your problem is that you haven't separated your concerns between the form and the control properly.
Since you have a (somewhat generic) control, it shouldn't depend on the form. All of the logic of the control should reside within the control itself. The form should only black-box consume the control: add it, set public fields, call public methods, etc. anything else is a violation of encapsulation.
Sometimes, controls may need to know things about their parent form. In this case, I would suggest something as simple as adding a Parent field to the child control.
if you need something more specific from the form, you can always add an interface; the interface should only list those things that the control needs from the form. For example, if you need the size, you can add:
public interface IControlParent {
int Width { get; }
int Height { get; }
}
This way, you clearly see the dependencies (what the control needs from the parent), and if the parent type/contract changes, you don't need to do as much to change your control class.
You must sepárate your code, its never a good idea to have a reference to an application assembly, if you try to reuse it in the future, the applications exe should go with the control.
So, take the class from the form project and move it to the control project or create a library project, put the class on it and reference it from your control and your app projects.
You should use an event (delegate). Let's assume that inside your form project you created one class: Form1. And inside user control you defined UserControl1.
UserControl1 needs to instantiate and call a method from Form1:
public class Form1
{
public void Execute(string sMessage)
{
Console.WriteLine(sMessage);
Console.ReadLine();
}
}
UserControl1:
public class UserControl
{
public Func<object, object> oDel = null;
public void Execute()
{
oDel?.Invoke("HELLO WORLD!");
}
}
And from the class that instantiate UserControl, let's call it ParentClass:
public class ParentClass
{
public void Execute()
{
UserControl oUserControl = new UserControl();
oUserControl.oDel = Form1Action;
oUserControl.Execute();
}
public object Form1Action(object obj)
{
string sObj = Convert.ToString(obj);
Form1 oForm = new Form1();
oForm.Execute(sObj);
return null;
}
}
This approach gives the responsibility of handling an event to the high level class.
First of all, here is the simple application I build using C# in Visual Studio 2010, the filename is program.cs, all process will be displayed in command prompt.
public static void Main(string[] args)
{
int input = Convert.ToInt32(Console.ReadLine());
switch (input)
{
case 1:
Console.WriteLine("A");
break;
case 2:
Console.WriteLine("B");
break;
case 3:
Console.WriteLine("C");
break;
default:
Console.WriteLine("default");
break;
}
}
I want to build a GUI to make it more user friendly.
I created a form with a ComboBox, a Label, and a Button. The values in the ComboBox are [1,2,3,default]. I want to let the user select a value in the ComboBox, hit the Button, and the program will update the label to [A,B,C,default].
How can I keep the logic in program.cs, and achieve the above goal?
I created a form and visual studio generate a Form1.cs that looks like this
namespace quickTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
}
So I think the problem I ran into is I don't know how program.cs can get/set value of Form1
In Main(), I added Application.Run(new Form1()); so it runs the form instead of command prompt, but then I'm stuck. I tried comboBox1.SelectedValue but I can only get value in From1.cs and not program.cs, I need it to be in program.cs so I can apply the logic.
Just for clarification, this is just a sample I build. The actual program.cs contains a lot more logic but I don't think it's affect what I want to do here so I didn't put it in the description. I need a way to get and set value from program.cs to the form.
I don't believe the best solution is adding a GUI to a console application, but I've been in a similar situation before and was able to do it successfully. The best option would be to refactor the logic into libraries that could be referenced from a separate GUI application.
Create events in the form class and subscribe to them from program.cs to drive the logic that needs to happen. You can pass values to and from the logic with your EventArgs class. That is essentially what you do when you write the code that drives a form, you're just offloading it to a separate class.
Update: Added Example Code
This is basic event-based programming. Through the use of generics we can greatly reduce the amount of boilerplate code, but it would be good to get an understanding of the delegates we're creating automatically through generics. Shortcuts can be a hindrance if you don't understand how they work (or don't) when bugs arise.
Events how to: http://msdn.microsoft.com/en-us/library/w369ty8x.aspx
Generic delegates: http://msdn.microsoft.com/en-us/library/sx2bwtw7.aspx
For an example I created a pair of forms. MainWindow has a textbox OutputBox, and DetachedForm has a combobox OptionComboBox and a button TriggerButton, which we will use to fire the event.
MainWindow Class:
public partial class MainWindow : Form
{
public MainWindow()
{
InitializeComponent();
DetachedForm detachedForm = new DetachedForm();
detachedForm.SelectionMade += new EventHandler<SelectionMadeEventArgs>(detachedForm_SelectionMade);
detachedForm.Show();
}
void detachedForm_SelectionMade(object sender, SelectionMadeEventArgs e)
{
OutputBox.Text = e.ActualSelection;
}
}
DetachedForm Class
public partial class DetachedForm : Form
{
public event EventHandler<SelectionMadeEventArgs> SelectionMade;
public DetachedForm()
{
InitializeComponent();
}
private void OnSelectionMade(SelectionMadeEventArgs e)
{
EventHandler<SelectionMadeEventArgs> handler = SelectionMade;
if (handler != null)
{
handler(this, e);
}
}
private void TriggerButton_Click(object sender, EventArgs e)
{
if (OptionComboBox.SelectedItem != null)
{
SelectionMadeEventArgs args = new SelectionMadeEventArgs(OptionComboBox.SelectedItem.ToString());
OnSelectionMade(args);
}
}
}
public class SelectionMadeEventArgs : EventArgs
{
public SelectionMadeEventArgs(String actualSelection)
{
ActualSelection = actualSelection;
}
public String ActualSelection { get; set; }
}
You can expose a public function or property in Form1.cs that gets/sets the value of the combo box, then in program.cs you can access that function to set or get the combo box.
How does one access WinForm controls such as ProgressBar properties from another class?
Please see my code below. I know this might not be the best option to expose WinForm class and its members as public but I am trying to clear the concept at this point.
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e)
{
Class1 c = new Class1();
c.loop();
}
public void PBSetup()
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 100;
}
public void PBUpdate(int recno)
{
progressBar1.Value = Class1.recno;
}
}
}
namespace WindowsFormsApplication1
{
class Class1
{
public static int recno;
public void loop()
{
//How do I access Form1.PBSetup()??
for (recno = 0; recno <= 100; recno++)
{
//How do I access Form1.PBUpdate(recno)??
}
}
}
}
You do not want your business logic (your class) interacting with your UI (your form). The business logic should be agnostic of the presentation layer.
If you want the form to respond to things that happen inside the class, you could consider exposing an Event inside the class that the form could subscribe to, much like it would subscribe to a button's click event. The class instance could fire off the event completely unaware of who might be listening, and any subscribers would be notified.
This looks like a big time code smell :).
You would need an instance of Form1 inside of Class1 in order to PBUpdate.
Something tells me what you are doing is just not right.
Explain what you are trying to do and we can help. Otherwise there is no way to access PBUpdate unless you either made it a static function where you could call it like Form1.PBUpdate() or you had an instance of Form1 within your class Class1
You can change the access modifiers of the progress bar from private to Internal or public , you can do this operation from properties pane .
Keep in mind that you have to pass to the second class the instance of the form and then you can change the value of the progress bar directly from the second class.
However is a tricky solution, the best should be keep the presentation layer implementation separated and work with an event.
I do not recommend to use this method, for simple reason as mentioned here by one of the comments. But if you really want to access that form control, here is how:
1) Select that control and set its access modifier to internal.
2) Assume your form id is "Form1" and control id is "control1"
Inside your method:
Form1 form = (Form1)Application.OpenForms["Form1"];
// form.control1 should now be available.
This should be quite simple really - not sure what the problem is.
I have a C# Class (Public.cs) and a windows form (Form1.cs). Through a function in Public.cs, I want to get the value of a control on Form1 (without having to use object parameters).
// This code appears in Public.cs
public string MyFunction(int num_val)
{
if (chk_num.checked == true)
{
// Something here...
}
}
The issue is that my class cannot find the control on my form. Is there some way that I must reference it in C#?
Thank you.
I would strongly suggest exposing the Checked property via a specific property on Form1 (perhaps with a more meaningful name). This will help to hide the implementation details (i.e. control structure) of the Form1 from it's caller and instead expose only the logic that is required for other consumers to do their job
For example:
public bool IsNumberRequested
{
get { return chk_num.Checked; }
}
Or alternatively, if you still really want to access the control directly, from the designer you can select the control and change it's Modifier property to public (or something else) enabling you to access the control object using the code you originally wrote above.
EDIT: (Response based on comment)
Public.cs will still need a reference to Form1 and then will call the IsNumberRequested property of that object.
// Public.cs
public class Public
{
private Form1 _ui;
public Public(Form1 ui) { _ui = ui };
public string MyFunction(int num_val)
{
if (_ui.IsNumberRequested)
{
// Stuff
}
// Else, default Stuff
}
}
Alternatively, you could pass the form as a parameter to the MyFunction too rather than using it as an instance variable.
I would have the set up the other way around
public class Public
{
public bool CheckNumber {get;set;}
public string MyFunction(int val)
{
if(CheckNumber)
{
//do that thing
}
return ...
}
}
public partial class Form1 : Form
{
Public myinstance = new Public();
public Form1()
{
InitializeComponent();
}
private void CheckBoxChanged(object sender, EventArgs e)
{
myinstance.CheckNumber = chk_num.checked;
}
}
You'll need to assign CheckBoxChanged to the OnChanged event handler for your check box (which I'm assuming is chk_num.
This way your class Public doesn't rely on a form, which it shouldn't.
As Reddog says, use better names, although I half suspect you've just given example names in your question.
How can I make a textbox in my winforms application that accepts new lines of text from anywhere in the application?
I have a main form that contains a textbox. I'd like to directly add text to the box from a method in another class.
Update
I tried this in my main form:
public void Output(String value)
{
if (txtOutput.Text.Length > 0)
{
txtOutput.AppendText(Environment.NewLine);
}
txtOutput.AppendText(value);
}
But I can't call Output from the other class. I'm new to C#, so perhaps I'm missing something obvious.
Regards, Miel.
PS Yes, I know this is bad design, but for now this seems to be the best way to do what I want. The textbox would function like a console.
You'll need to expose the Text property of the TextBox as a string property on your form. For example...
public string TextBoxText
{
get { return textBoxName.Text; }
set { textBoxName.Text = value; }
}
Edit
After reading the question edit, your problem is that you need a reference to a specific instance of the form whereever you're trying to execute that code. You can either pass around a reference (which is the better option), or you could use some smelly code and have a static property that refers to one instance of your form. Something like...
public partial class MyForm : Form
{
private static MyForm instance;
public static MyForm Instance
{
get { return instance; }
}
public MyForm() : base()
{
InitializeComponent();
// ....
instance = this;
}
}
Using this approach, you could call MyForm.Instance.Output("test");
In order to decouple a bit more you could inverse the control a bit:
// interface for exposing append method
public interface IAppend
{
void AppendText(string text);
}
// some class that can use the IAppend interface
public class SomeOtherClass
{
private IAppend _appendTarget = null;
public SomeOtherClass(IAppend appendTarget)
{
_appendTarget = appendTarget;
}
private void AppendText(string text)
{
if (_appendTarget != null)
{
_appendTarget.AppendText(text);
}
}
public void MethodThatWillWantToAppendText()
{
// do some stuff
this.AppendText("I will add this.");
}
}
// implementation of IAppend in the form
void IAppend.AppendText(string text)
{
textBox1.AppendText(text);
}
It looks like your design is a little bit corrupted. You shouldn't let buisness logic mess with GUI controls. Why don't you try a return value and assigning it on the interface side?
This is a REALLY bad way of doing it, but just to make sure all the answers are out there...
In the VS designer, each form control has an item in the Properties window named Modifiers that defaults to Private. Changing this to one of the others settings, such as Internal or Public, will let you access it from outside the form.
I must stress that this is the worst way to do it.