Sort Listview with a Combobox [closed] - c#

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
What I want is to type in a textbox before I start my packet sniffer to only show me results that I want. This is what I have but it isn't working. I want this listview to just show port 3074 using a textbox does anyone know how to do this? This is a packet sniffer
(source: gyazo.com)
Anyone know how I can do that?
This is what I am using
namespace Network.Packet.Analyzer.App.Forms.Main
{
public partial class FrmAnalyzer : Form, IAnalyzer
{
public FormaAnalyzerPresenter _presenter;
public FrmAnalyzer()
{
InitializeComponent();
_presenter = new FormaAnalyzerPresenter(this);
}
//callled when ListView control selection being made
private void lstReceivedPackets_SelectedIndexChanged(object sender, EventArgs e)
{
_presenter.CreateDetailedTree();
}
//start button click event method
private void toolStripButton1_Click(object sender, EventArgs e)
{
_presenter.StartClicked();
}
//stop button click event method
private void tbtnStop_Click(object sender, EventArgs e)
{
_presenter.StopClicked();
}
private void Form1_Load(object sender, EventArgs e)
{
_presenter.ApplicationStarted();
}
// clear all button click event method
// clearing buffer,listvie control,and treeview
private void tbtnClearAll_Click(object sender, EventArgs e)
{
_presenter.ClearAllClicked();
}
private void closeToolStripMenuItem_Click(object sender, EventArgs e)
{
ApplicationClose();
}
private void menuAlwaysOnTop_Click(object sender, EventArgs e)
{
_presenter.TopMostClicked();
}
#region IAnalyzer Members
public ListView ListReceivedPackets
{
get { return lstReceivedPackets; }
}
public ListView ListOpenPorts
{
get
{
return lstOpenPorts;
}
}
public ProgressBar ProgressBufferusage
{
get { return progressBufferUsage; }
}
public TreeView TreePackedDetails
{
get { return treePacketDetails; }
}
public void SetTotalPacketReceivedText(string strNumber)
{
if (strNumber != null)
lblTotalPkgsReceived.Text = strNumber;
}
public void SetBufferUsage(string strNumber)
{
if (strNumber != null)
lblBufferUsage.Text = strNumber;
}
public void SetReadyText(string text)
{
if (text != null)
lblStripReady.Text = text;
}
public bool ButtonStartEnabled
{
get { return tbtnStar.Enabled; }
set { tbtnStar.Enabled = value; }
}
public bool ButtonStopEnabled
{
get { return tbtnStop.Enabled; }
set { tbtnStop.Enabled = value; }
}
public bool TopMostChecked
{
get
{
return topMostMenuItem.Checked;
}
set
{
topMostMenuItem.Checked = value;
}
}
public bool FormShowAsTopMost
{
get
{
return this.TopMost;
}
set
{
this.TopMost = value;
}
}
public void ApplicationClose()
{
this.Close();
}
public StartupInfo StartupInformation
{
get
{
return _presenter.StartupInformation;
}
set
{
_presenter.StartupInformation = value;
}
}
public void ShowErrorMessage(string message)
{
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
public void ShowWarningMessage(string message)
{
MessageBox.Show(message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
public void ShowDefaultErrorMessage()
{
MessageBox.Show("Unexpected error has acquired", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
public void ShowDefaultErrorMessage(Exception ex)
{
MessageBox.Show(String.Format("Unexpected error has acquired. Error message: {0}", ex.Message), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
public void ShowErrorMessage(string message, Exception ex)
{
MessageBox.Show(String.Format("{0}. Error message: {1}", message, ex.Message), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
public void Invoke(Action act)
{
this.Invoke(new MethodInvoker(delegate { act(); }));
}
private void button1_Click(object sender, EventArgs e)
{
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
}
}
#endregion
This is the other part: pastebin.com/rPWMJHCe

Okay, seeing your code from pastebin, i will keep my answer rather simple. My answer is most certainly not the best and not the most elegant, and you will certainly still hit a wall here and there, but making it better and easier to work with would most likely require abandoning ListView in favor of a more capable control (such as DataGridView, for example). Anyway...
For the example given below, i'll pick the ListView ListOpenPorts. But of course you can adapt this approach to other ListViews as well, just pay attention to keep track of where which data is stored inside the ListViewItems.
The basic idea of a filtered content display is something ListView doesn't really like. It is not so much the filtering itself, but the fact that all items must be somewhere when we change or switch off filtering. What makes ListView suck so much in this regard is that it insists to maintain the list of items internally instead of giving us the opportunity to control and swap that list easily (hence me pointing towards DataGridView earlier).
The approach involves maintaining another private list _listOpenPortItems in the class FrmAnalyzer which will keep all 'open port' ListViewItems. This is necessary so our code can access them and feed them back into the lstOpenPorts ListView whenever the filtering is switched off or changed.
private readonly List<ListViewItem> _listOpenPortItems = new List<ListViewItem>();
To always have the correct items in the _listOpenPortItems list requires to not access ListOpenPorts.Items directly. Instead, methods will be implemented in the class FrmAnalyzer which will realize equivalent functions for any function used on ListOpenPorts.Items before. Those methods manipulate the private list _listOpenPortItems and also add/remove items to/from the actual ListView control depending on the filter settings.
Also note the two properties IsPortFilterEnabled and PortToFilter, which control filtering and which i will explain a bit later.
public void AddOpenPortItem(ListViewItem openPortItem)
{
_listOpenPortItems.Add(openPortItem);
if (!IsPortFilterEnabled || PortToFilter == openPortItem.SubItems[3])
lstOpenPorts.Items.Add(openPortItem);
}
public void RemoveOpenPortItem(ListViewItem openPortItem)
{
_listOpenPortItems.Remove(openPortItem);
if (!IsPortFilterEnabled || PortToFilter == openPortItem.SubItems[3])
lstOpenPorts.Items.Remove(openPortItem);
}
//...Also implement here methods for all other functions of
//...ListOpenPorts.Items you used before (such as RemoveByKey, ContainsKey, etc...)
//...which will have to realize the equivalent function on _listOpenPortItems.
//...Any method which can potentially alter _listOpenPortItems will have to have a
//...code snippet like:
// if (!IsPortFilterEnabled || PortToFilter == openPortItem.SubItems[3])
// lstOpenPorts.Items.XXXXXX(openPortItem);
//
//...(where XXXXXX is the appropriate method of lstOpenPorts.Items)
(Note that i here assume the port number being the subitem with index 3.)
With those methods implemented, just replace all direct accesses of ListOpenPorts.Items with the respective method calls. For example:
_view.Invoke(() => _view.ListOpenPorts.Items.Remove(item));
would be replaced with:
_view.Invoke(() => _view.RemoveOpenPortItem(item));
This code change sound like difficult work, but it is actually not that hard and just a question of finding all usages of "ListOpenPorts"/"ListOpenPorts.Items" - a simple text search through your whole source code is the bigger part of the job.
To control the filter we will use the two properties i already mentioned: PortToFilter, a String property which will hold the port number to filter for; and IsPortFilterEnabled, a bool property denoting whether the filter is enabled or not.
Both properties are, like the methods above, implemented in the class FrmAnalyzer.
public bool IsPortFilterEnabled
{
get { return _isPortFilterEnabled; }
set
{
if (_isPortFilterEnabled != value)
{
_isPortFilterEnabled = value;
RefreshOpenPortListView();
}
}
}
private bool _isPortFilterEnabled = false;
public string PortToFilter
{
get { return _portToFilter ; }
set
{
//
// Note that setting PortToFilter will turn on the filter
//
if(!_isPortFilterEnabled || _portToFilter != value)
{
_portToFilter = value;
RefreshOpenPortListView();
}
}
}
private string _portToFilter = "0";
Remark: It would be better to handle port numbers as what they are - int numbers, not strings. But since you already use strings for port numbers, i chose the string data type here, too.
You might notice the calls of method RefreshOpenPortListView. This is a method which updates lstOpenPorts.Items according to the filter settings.
private void RefreshOpenPortListView()
{
//
// Note that this method does not preserve the current selection in the List View.
// If you need to preserve it, save the current selection here and restore it
// at the end of this method again.
//
IEnumerable<ListViewItem> itemsForListView =
(_isPortFilterEnabled) ?
_listOpenPortItems.Where(item => PortToFilter == item.SubItems[3])
: _listOpenPortItems;
lstOpenPorts.BeginUpdate();
_lstOpenPorts.Itmes.Clear();
foreach(ListViewItem item in _itemsForListView)
_lstOpenPorts.Add(openPortItem);
_lstOpenPorts.EndUpdate();
}
(Note that i here assume the port number being the subitem with index 3.)
Finally, how do you set IsPortFilterEnabled and PortToFilter? Here one idea briefly outlined, but there a numerous different ways of how to do that:
Let a checkbox toggle the value of IsPortFilterEnabled. This checkbox basically enables/disables the filtered view.
Let a (numerical) textbox dump its content into PortToFilter. This textbox contains the port number to filter for. Note that (according to my suggested implementation) whenever the textbox transfers its content to PortToFilter, the filtered view is enabled and updated.

You want to sort or filter?, your title says sort, but your description says "to just show those results"
If your Listview is bound to a DataTable, then you can filter or sort using the DefaultView property.
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == 0)
dtItems.DefaultView.Sort = "ID";
else
dtItems.DefaultView.Sort = "Name";
MyBindMethod(dtItems);
}
Or if you want to filter by ID
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
dtItems.DefaultView.RowFilter = "ID = '" + comboBox1.SelectedValue + "'";
MyBindMethod(dtItems);
}

Related

Combobox value not saving for 1 specific client

Not sure if anyone can be of help here, but I have a comboxbox bound to a viewmodel property, on a form who's value is set by an event. It is working in house, but there is one client where the event fires, the value is set (I know because I added some logging), but their screen is not updated. I have a copy of the database, and I mirror the steps and it works. Any ideas why that could be happening? I included the code below, but it is pretty basic.
private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "TriggerId")
{
Method();
}
}
private void Method()
{
ComboBoxSelectedProperty = null;
if (TriggerId != null)
{
var object = Work.ObjectStore.GetById((int)TriggerId);
if (object != null)
{
ComboBoxSelectedProperty = Work.AssociatedObjectStore.GetByObjenct(object);
}
NotifyPropertyChanged("ComboboxSourceSource");
}
}
}

c# - StackOverFlowException when mentioning ListBoxt?

I'm trying to get a new form (FormAlbum) to open when I click buttonOpenAlbum and have an item selected in the AlbumListBox.
If I just have this in buttonOpenAlbum_Click:
private void buttonOpenAlbum_Click(object sender, EventArgs e)
{
FormAlbum MusicForm = new FormAlbum(this);
MusicForm.ShowDialog();
}
The new from opens without error. However, as soon as I mention "AlbumListBox.SelectedItem" (as in the code belowin Form FormMain), I get a "StackOverflowException was unhandled" at:
public ListBox AlbumListBox
{
get
{ // <-This bracket here is where the error highlights
I don't understand why I'm getting this error, only that it must have something to do with AlbumListBox. What am I doing wrong? Any help is appreciated, thank you.
Form FormMain:
public FormMain()
{
InitializeComponent();
}
private void buttonAddAlbum_Click(object sender, EventArgs e)
{
FormAlbumAC addAlbumForm = new FormAlbumAC(this);
addAlbumForm.ShowDialog();
}
private void buttonOpenAlbum_Click(object sender, EventArgs e)
{
if (AlbumListBox.SelectedItem != null)
{
MessageBox.Show(AlbumListBox.SelectedItem.ToString());
FormAlbum MusicForm = new FormAlbum(this);
MusicForm.ShowDialog();
}
else
{
MessageBox.Show("You need to select an album from the list to open.");
}
}
public static class PublicVars
{
public static List<Album> AlbumList { get; set; }
static PublicVars()
{
AlbumList = new List<Album>(MAX_ALBUMS);
}
}
public ListBox AlbumListBox
{
get
{
return AlbumListBox;
}
}
Look at your property implementation:
public ListBox AlbumListBox
{
get
{
return AlbumListBox;
}
}
It's just calling itself, recursively. It may be easier to see that if we convert it to a method:
public ListBox GetAlbumListBox()
{
return GetAlbumListBox();
}
That's why you've got an overflow. It's not clear what you meant it to do... where did you expect the value to come from? You probably need a variable to back the property. What did you expect to set the value returned?
I'd also strongly discourage the design of the PublicVars class. Aside from the naming, you're basically using global variables - not a good idea. Work out which classes need access to the data, and how to get that data to them appropriately.

Update entire Winform

I'm a beginner at C# who's decided to create a textbased adventure game in a Winform, but I've been struggling with updating the form whenever it needs to update. In the past, I have used something.Invalidate(); to update an image, but apparently that doesn't work for an entire form.
I have a set of labels that display text based on an integer and whenever the value of the integer updates, I'd like the form to show that.
What I have tried thus far:
public partial class GameWindow : Form
{
public void buttonInventory_Click(object sender, EventArgs e)
{
Basic.HP = Basic.HP++;
this.Refresh();
}
}
While the HP updates, the form doesn't show it. Is there anything else I should use than Refresh();? A lot of googling mostly resulted in explanations about Backgroundworkers, but do I really need another thread for something as simple as this?
Why not just make a separate routine for updating values, that you call after every value change. IE: (Note - I don't program in C#):
public partial class GameWindow : Form
{
public void buttonInventory_Click(object sender, EventArgs e)
{
Basic.HP = Basic.HP++;
updateValues();
}
public void updateValues()
{
hp.text = HealthInteger;
basic.text = BasicInteger;
}
}
And call this for evey value change.
A label can't be bind to a string value like an image can be to a picture box.
The simplest solution here is too explicitly set the Text property of the label each time your HP property is changed :
private void RefreshFormWithModel(Basic basic)
{
labelHP.Text = basic.HP;
}
public void buttonInventory_Click(object sender, EventArgs e)
{
Basic.HP = Basic.HP++;
this.RefreshFormWithModel(Basic);
}
If you really want complex binding, here is some lectures.
I'm going to assume the class name of Basic is just Basic
in the class Basic
private int hp;
public int HP
{
get { return hp; }
set { hp = value; HP_Changed(); }
}
public event EventHandler HPChanged;
private void HP_Changed()
{
if (HPChanged != null) { HPChanged(this, new EventArgs()); }
}
in the GameWindow
//where ever you create a new Basic, add to the event handler
Basic Basic = new Basic();
Basic.HPChanged += Basic_HPChanged;
private void Basic_HPChanged(object sender, EventArgs e)
{
Basic b_sender = (Basic)sender;
int NewHealth = b_sender.HP;
//Update whatever value needs to be updated, here
}
Then whenever the HP of the Basic is changed, it will fire an event in the GameWindow to update the appropriate field.

Infinite Loop error thrown when using property accessors in C#

I have a second window which opens when a certain staffname is searched for, this window prompts you to choose between the 2 staff members with the same name. The window then needs to return a value to the parent window to populate a datatemplate with relating data from the xml file.
I've tried to create a string which will be updated with a value depending on which button is clicked, this string can then be returned to the calling method on the first window and populate binding data in the Linq to Xml query.
But when it runs it causes a stackoverflow exception and that it could be an infinite loop. I'm not sure enough about c# to know what to change.
public partial class Choice : Window
{
private string StaffChoice;
public Choice()
{
InitializeComponent();
}
public string staffChoice
{
get { return this.StaffChoice; }
set { staffChoice = StaffChoice; }
}
private void btnMRG_Click(object sender, RoutedEventArgs e)
{
StaffChoice = "MRG";
this.Close();
}
private void btnRPG_Click(object sender, RoutedEventArgs e)
{
StaffChoice = "RPG";
this.Close();
}
}
Any help or suggestions would be great!
Thanks in advance!
Firstly, your naming conventions are wrong - the field should be called staffChoice and the property should be called StaffChoice. Please read the .NET naming conventions for more information. However, now look at your property closely:
public string staffChoice
{
get { return this.StaffChoice; }
set { staffChoice = StaffChoice; }
}
What do you think the setter does? There are two problems with it:
It ignores the value that you're trying to set it to.
It calls itself recursively.
You could fix this by keeping the manually-declared field, fixing the naming conventions, and changing the property to set the variable to value like this:
private string staffChoice;
public string StaffChoice
{
get { return staffChoice; }
set { staffChoice = value; }
}
However, it would be simpler to use an automatically implemented property:
public string StaffChoice { get; set; }
This will create the backing field and the getter/setter for you automatically.
The simplest way is to declare a property like this...
public string StaffChoice { get; set; }
your problem is you are basically calling the property setter from within the same setter - thus you have a recursive loop. You could change your code like this to make it work...
private string StaffChoice;
public string staffChoice
{
get { return this.StaffChoice; }
set { StaffChoice = value; }
}
Your setter isn't right, you are assigning a value to itself (causing the infinite loop) and not using value.
You should change your code to this, your naming convention looked backwards so I corrected it, hope you don't mind:
private string staffChoice;
public Choice()
{
InitializeComponent();
}
public string StaffChoice
{
get { return staffChoice; }
set { staffChoice = value; }
}
private void btnMRG_Click(object sender, RoutedEventArgs e)
{
staffChoice = "MRG";
this.Close();
}
private void btnRPG_Click(object sender, RoutedEventArgs e)
{
staffChoice = "RPG";
this.Close();
}
Your property should be:
public string staffChoice
{
get { return this.StaffChoice; }
set { this.StaffChoice = value; }
}
In your code you are calling the setter again in the setter - hence the infinite recursion.
However, as you are not doing anything special in the setter (like notifying the UI that the property has changed you could simply have:
public string staffChoice { get; set; }
This "auto property" is a little cleaner.
(BTW: the normal practice is to have the back variable starting with a lower case letter and the public property starting with an upper case one. However, if you are consistent in your application it doesn't really matter.)

How can I run a method from a another winform in c#?

I have an "addEngine" method in a form called Products and i have an "Add New Engine" button.
public partial class Products : Form
{
public void addEngine(short EngineID, string NumberPerUnit, string Manufacturer, string ModelSeriesYear)
{
try
{
productCurrentRow = ((DataRowView) productEngineBindingSource.Current).Row;
int productID = (int) productCurrentRow["ProductID"];
var engines = from engine in productDataset.ProductEngine
where engine.ProductID == productID
select engine;
foreach (var engine in engines)
{
if (engine.EngineID == EngineID)
{
UC.alertError("Record already exists!");
return;
}
}
var newEngineRow = productDataset.ProductEngine.NewProductEngineRow();
newEngineRow.EngineID = EngineID;
newEngineRow.ProductID = productID;
newEngineRow.NumberPerUnit = NumberPerUnit;
newEngineRow.Manufacturer = Manufacturer;
newEngineRow.ModelSeriesYear = ModelSeriesYear;
productDataset.ProductEngine.AddProductEngineRow(newEngineRow);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void btnAddNewEngine_Clicked(object sender, EventArgs e)
{
EngineFilter eginfilter = new EngineFilter();
eginfilter.ShowDialog();
}
}
When the buttion is clicked there is another form called "EngineFilter", which loads a list Engines. After user selects an item from the list and clicks "Select" buttion on the form, the information of the item is inserted a list (ProductEngine datatable) through the "addEngine" method on the "Product" form. The problem is that i cannot pass the parameters between the two forms(classes)
public partial class EngineFilter : Form
{
public delegate void addEnineDelegate(short EngineID, string NumberPerUnit, string Manufacturer, string ModelSeriesYear);
private void btnSelect_Click(object sender, EventArgs e)
{
Products product = new Products();
DataRow row = ((DataRowView) engineFilterBindingSource.Current).Row;
addEnineDelegate mydelegate = new addEnineDelegate(product.addEngineMethod);
mydelegate((short)row[2], "1", row[0].ToString(), row[1].ToString());
this.Close();
}
}
I've tried to use a delegate but there is a "Object reference not set to an instance of an object" error. Is there anybody can give me a good practice to handle this?
You could pass a reference to the form which contains the addEngine method to the form which you want to call this method from, and that would work, but is not a particularly great solution.
Better would be to have a class which exposes this method, then pass the instance of this class to both forms for them to use. This has better separation of concerns. Really your form should not be responsible for updating the repository, what it should do is collect the user input and pass it to the class responsible for doing the update.
I aggree with Sam Holder, but if you want this code to work as it is right now, I would use events.
Create your event in the EngineFilter
Public event EventHandler<EngineFilterEventArgs> EngineFilterSelected;
Now second step is to create the EngineFilterEventArgs class and put every parameter you want in the eventargs. Now I have just added an ID
Public class EngineFilterEventArgs : EventArgs
{
Public int Id {get; set;}
Public EngineFilterEventArgs(int id)
{
Id = id;
}
}
Third step is to fire the event. Note that 1 is selectedId
If(EngineFilterSelected != null)
EngineFilterSelected(this, new EngineFilterEventArgs(1));
Now make sure that the other form is listening to the event.
private void btnAddNewEngine_Clicked(object sender, EventArgs e)
{
EngineFilter enginFilter = new EngineFilter();
engineFilter.EngineFilterSelected += handler;
engineFilter.ShowDialog();
}
Final step is to add your eventhandler
Protected void handler(object sender, EngineFilterEventArgs e)
{
//TODO Handle your event
Int selectedId = e.Id;
}

Categories

Resources