Design Pattern /ListBox.Items.Count - c#

i built an Winform application with Pcapdot.Net DLL's that take Pcap file and play all the file packets into the machine network card.
recently i have notice that all my main form (where all the buttons clicks\events) is a mess, i putt all the method inside those function and the code looks complicated and it's hard to understand so i started to rearrange this code.
because my application has Listbox where all the played files is inside i put all this play function inside the Play button for example: i have loop over my Listbox.Items.Count and inside i am handle this files. now i want to do something different and this is my question:
is it common way to define class that handle this Play function and from the main form every time that file added to my Listbox just fire up the event ControlAdded or after remove file ControlRemoved and put this files into my class who has List that hold this file ?

I think you would be better off rearranging it more like this (to separate the business logic from your UI):
Have a public method inside your Form class that returns an IEnumerable<string> which is the list of files, called something like SelectedFiles().
Make a public event property for the "Play" button which is raised when the user clicks the "Play" button, called something like PlayClicked.
Make a "controller" class which is responsible for creating and showing the form.
Your controller class would attach to the PlayClicked event. The controller's handler for PlayClicked would call the form's SelectedFiles() method to get the list of files, and would then do whatever it needs to do.
I would even consider wrapping the handling code for the selected files into another class called something like SelectedFileHandler and put the logic for handling the files into that, perhaps in a method called HandleFiles(IEnumerable<string> files).
Then the "controller" class would still be hooked up to the PlayClicked event, but it would use the SelectedFileHandler.HandleFiles() method to handle the files.
Does this make some sense to you? I could be misunderstanding what you're looking for.
I'm basically saying that you should use a Model View Controller or a Model View Presenter architecture.

Related

Passing Details From One Window to Another Window

I have a selection of TextBoxes that a user fills in when they wish to note that they have had contact with another person. Most of the TextBoxes are imply filled in by typing into them. However, for one of them I would like the user to be able to select from a list of People that appears when they click on a button.
This is where I am having problems. So far I have just made a DataGrid appear and handled it's SelectionChanged method to fill in the TextBoxes text property. This has worked fine, however now there is not enough space on the current page to show an entire DataGrid with all the people they can select from.
I've decided to show the People in a separate, smaller Window that appears when the user clicks a Button. The issue I have is that when the user selects the Person they wish to mark the contact for in the new Window, I have no idea how I can notify the original Window that a Person has been selected, close the new smaller Window and fill in the appropriate TextBox on the original Window.
What would be the most intuitive way to fill in the TextBox on the original Window, based on the selection on the Window that opens?
I would use delegates,which call a function of the original window and parse the changed variable with it. So you know when the user clicked something and you can directly react to this "event".
Link:
https://msdn.microsoft.com/en-us/library/ms173171.aspx
If you use a framework like Galasoft's MVVM Light (http://www.galasoft.ch/), they have a messenger system just for this purpose. It allows you to "broadcast" messages that can be "received" by any other part of the application
This is when considering using Domain, Model, Presentation (Winforms/WPF version of MVC formatting) to do your app.
You can have each form as its own class, well they are their own class. Create each form class but add some public members to it if the controls are private. Have them have "get" properties only and to return the values of whatever controls or variables are in that form. Your main form will be the controlling form. All forms will be handled by the main form so when you open it, it is a class the main form can access.
Now, if I remember (been doing more MVC and not any Winforms lately) I believe if you use the ShowDialog() method it will freeze the main thread so when you close out the main form you can continue and read in public members you have in your forms class you opened. Synchronous I believe it runs as. If you use just Show() the thread will keep on trucking, asynchronous. With asynchronous you may then have to use a main form in your startup code so there is always a window there but subscribe to the close event of your forms and have a method that can grab those public members out. Be sure to instantiate the extra forms at the root of the main class so it doesn't fall out of scope when it exists the method that calls it. You may even be able to make the method that calls is a async call and have an await before the command that runs the Show method on the form.
Summary, treat each form as its own class but add public members that can read the values from the controls and/or variables you want. Read that data from the class when it closes via an event or synchronously when the thread closes out from the form closing. The form closing doesn't discard the object, just the visualization of the form.
Oh, if you are passing info from the main form to a child for you are opening, either add a constructor for that form class that takes your input as a model or values to fill in the appropriate variables or forms before showing it or create a public property you can put your values you want to send in before showing the class.
Remember, everything is a class, once you look at it as such and treat it as such, the answer will come. :-)
I should warn, I am a long winded explainer.
At work putting all this down from memory so some errors may exist. Let me know if there are.
I think the problem is to access the controls of the main window, isn`t it?
You can define an event of changing user`s choise and access MainWindow control by using the following construction:
((MainWindow)Application.Current.MainWindow).MyTextBox

How can I serialize wpf user control with xaml and code behind

I want to serialize wpf user control xaml and codebehind. XamlWriter.Save() only serialize's xaml so what can I do in this situation? My situtation is I have a usercontrol which include custom methods, subscribed events (ex: button click) When I deserialize usercontrol (for create usercontrol at runtime) I want to run that events and methods. Sorry my english isn't very good.
Just an idea, you can use MEF to built up a plugin structure for your user control. You want to create a user control on the fly but the event handler still should be hardcoded somewhere else in your project; with the plugin structure, you can just collect the plugin and reuse it; the events can be handled by a command something. Maybe giving a scenario and we can figure out more detail.
Plus, ISerializable provides a way for custom binary serialization for field, not for methods or events. Here is a related question:
What is the point of the ISerializable interface?
; on the other hand, you can still try some pattern like how the web control save its view state; for example
two virtual methods:
public virtual byte[] SaveState(); // it saves the states for your custom control
public virtual void LoadState(byte[] state) // it restore your state back to the control.
The custom code should be like:
byte[] state = controlA.SaveState(); // this method saves its own state.
YourControl controlB = new YourControl();
controlB.LoadState(state); // this method load the save state from A to B itself.
For the event, every event has a handler name, you can also serialize its handler name to the state and find it back by the saved name from its naming container alike. I don't have any experience to save the method.
If you still want to save and load state including fields, events and method, maybe serialization is not the proper way you are looking for I think.

Multiple classes in one form

I'm using a TabControl in my form and it made me wonder. Right now I have only two tabs and I store procedures relating to both tabs (button handlers, &c.) in the code for the main form, so it looks like this:
public partial class MainForm : Form
{
// ----------TAB1-----------
tab1SearchButtonCLick() {...}
tab1AddButtonCLick() {...}
// ----------TAB2-----------
tab2EditButtonCLick() {...}
tab2SearchButtonCLick() {...}
tab2ClearButtonCLick() {...}
}
That's not a problem now with so little code, but it might be one in the future. Is this an acceptable way of doing this? What's the alternative? I believe I could put the tabs in their own classes, but I'm not sure how I'm going to do that exactly (there's lots of controls in each tab that I'd have to pass as arguments to constructors).
You should move the contents of each tab to a separate UserControl.
Each UserControl should be a self-contained unit that gets whatever data in needs from the main form and fires events to tell the main form to do things.
The tabs have event for a reason - the tab raises the event and doesn't want to handle it.
When you use the tabs (or other objects with events) you need to write the code that handles the event.
If you really want, you can write the class in separate files so you can keep your own logic in separate files.
If you'll notice a Form is generated as a partial class by Visual studio.
That's because the design code is generated in a separate file.
You can do that yourself by declaring other parts of the class as partial in other files.
More about partial in this link

Implementing MVC/MVP Design for TabControl ..design question

I have a an Winform application with 2 forms.
In one form I have a Tab Control with 3 Tabs and navigation buttons to switch between tabs.
On the first tab the user selects a file and on navigating to next tab i want to do some
processing on the file selected in the first tab,and show the result in the 3rd tab.
The other form just invokes this form(start app.)
How can i do this using MVC/MVP ?
Currently i have created nested forms.
Starting application form creates instance of tab form and on SelectedIndexChanged on
the tab control and matching the selected tab property I'm doing the processing in the starting application form.and On closing on the tab form setting the result in the
starting application form.(which isn't ideal).
Edit : Also each tab contains a User Control which i have to initialize on tab change (refereeing to the data selected in the previous tab.)
Simple example is selecting a .zip file in the first tab , clicking next
will show the list of files within the zip file and in the third tab do processing with
the file selected in the 2nd tab.(there are better ways to do the same..just for sake of example.)
EDIT 2 : Basically I'm confused on how to get values from first tab via controller, do processing, and pass it to the next tab( via controller) and set the user control properties on the 2nd tab (via controller).Also the Tab titles are removed ..please see ..so the Tab form looks more like a wizard form. that's why i was using the SelectedIndexChanged property.
Basically i need to separate view and processing logic from the Winform.
Thanks All.
Odd choices for a UI. Anyhoo, there is no reason whatsoever to wait for SelectedIndexChanged to process the file. You might as well do it as soon as the file is selected. It will work better, the tab control becomes more responsive. If you wait until the event then the control will be frozen for a while as your UI thread is busy iterating the .zip file. The user will not consider this desirable.
Makes the MVC implementation a lot simpler too, whatever it might look like. Extra bonus is that you now no longer depend on the TabControl and can use whatever controls are best for the job.
Your Model will deal with your zip file in this case, e.g. methods like Print(), Extract() etc. and events like PrintCompleted and ExtractCompleted etc.
Your IView will expose methods and events that abstract your interaction with the UI behind an interface. So perhaps some methods such as DisplayFolderContents() and events like FileSelected() etc.
Your presenter will hook up to the Model and IView events and control which methods are called on each etc. The Form that you have a TabControl on is just an implemenation of the IView interface. You could have a different view just by injecting an implementation of IView into the Presenter, including a Mock IView for testing.
Values can be passed around the MVP pattern through the EventArgs you use.
/// <summary>
/// The event args for a selected file.
/// </summary>
public class FileSelectedEventArgs : EventArgs
{
public string FileName { get; private set; }
public FileSelectedEventArgs(string fileName)
{
this.FileName = fileName;
}
}
When the user selects a file, the FileSelected event is raised in your View, with the FileName available in the FileSelectedEventArgs. The Presenter listens for this event, and calls a method on the Model - maybe ExtractFile(string fileName), passing in the fileName from the FileSelectedEventArgs from the View.
The Presenter then listens to the ExtractCompleted event to be fired from the Model (which also has whatever custom eventargs you want) and calls the appropriate method on your View, passing in the parameters from the Model. The method in the View can do whatever you want in terms of displaying the data in a TabControl or in another way.
This is just one way of doing it anyway.

Winforms App Not Displaying Graphical Elements in Design Mode

I wrote a bunch of code in the .cs file in c# for a winforms application. The application runs fine, and everything is in it's place.
Something like this:
using..
namespace Temp
{
public class Temp : Form
{
Button b1;
TextBox t1;
Temp()
{
b1.Text = "Some Text";
b1.Size = new Size(50,20);
...
}
void function1()
{
// stuff
}
static void Main()
{
Application.Run(new Temp());
}
}
}
How can I modify my code (or fix it somehow) so that the design view displays the elements in their correct positions and view so that I can visually edit them instead of having to trial/error everything.
Edit for Clarification
My application runs fine. The problem is, that I didn't use designer to create the application and so in the designer view, the app is empty. But not empty when I run it, since everything is positioned programmatically in the .cs file. My question is, how can I fix this, so that the designer shows the objects correctly.
There is no quick fix other than to redesign everything?
So to get this shown within the designer you have to know how the designer works.
For every MyForm.cs there will automatically be a file called MyForm.Designer.cs be created. Within this Designer file there will be only one function called InitializeComponents(). This function will be called within the constructor of your MyForm.cs file.
The design viewer itself is responsible for the Designer file, so any change to this file while the design view is open would normally be discarded. Also if you put some code into the designer file that is not needed be the designer will be truncated.
So the next question is, when will this truncation happen? When you freshly open the design viewer of a form, it will read in everything from the Designer.cs file without making any changes. If you make any changes onto the form by the designer the complete file will be rewritten with all the settings already read in including your latest changes.
This behaviour can be monitored if you open the designer file also as source code view, make some little changes in design mode and afterwards take a close look at the left of the source file. There will be the changes marked with a yellow or a green marker.
Now after all this stuff of informations, you can try the following procedure to get your code into the designer:
Open the design view and put some simple control onto your form (e.g. TextBox)
Save and close the design view and open the Designer.cs file as source file
Copy all your variables name of your controls at the end of the file, right below the textBox1 line
Copy all your control property settings within the InitializeComponent() function right below the property settings of the TextBox
Copy all your control constructors to the top of the file, right below the constructor of the TextBox
Save the file and open your form in design view
Select the dummy TextBox on the design view and delete it
This change within the DesignView leads to a complete rewrite of the designer.cs file, ordering all your manually added stuff the right way.
So this is the way to go. Last but not least another little trick:
Every programmer uses the using-statement to not write the whole path to every class (like System.Windows.Forms.TextBox), but the designer writes always the whole path. To make it a little easier for your copy and paste session you can also add a using statement at the top of the file. After saving and changing something in Design View all this stuff will be re-written automatically. So you don't need to add all this paths manually while your adding your stuff to the Designer.cs file.
Your best option is probably to use the properties panel in the designer to set the positions etc (or maybe just drag them?).
You could go digging around in the designer file for the form (something.Designer.cs), but this isn't a fantastic idea because it can be pretty sensitive to changing things in ways the designer doesn't expect. Having said that, it looks like you're not actually using the designer to make your form (the class would be partial, for one thing), in which case you're SOL.
In that case, you need to copy the designer code from CS to designer.cs. So that you can use designer. I think this is the simplest approach.
Looks like this file was hacked from a class file instead of being generated by the system when you create a new winform.
You need at least an InitializeComponent(); call in your constructor. However you are missing a lot of other code that is generated for you when you create the file such as Dispose().
Best bet would be to right click your project in the solution explorer and click Add Windows Form then start over.

Categories