Advice on a simple Windows Form - c#

I have a VERY simple windows form that the user uses to manage "Stores".
Each store has a name and number, and is kept in a corresponding DB table.
The form has a listbox of stores, an add button that creates a new store, a delete button, and an edit button.
Beside those I have text boxes for the name and number, and save/cancel buttons.
When the user chooses a store from the list box, and clicks 'edit', the textboxes become populated and save/cancel become active. When the user clicks 'add', I create a new Store, add it to the listbox, activate the textboxes and save/cancel buttons, then commit it to the database when the user clicks 'save', or discards it when the user clicks 'cancel'.
Right now, my event system looks like this (in psuedo-code. It's just shorter that way.)
add->click:
store = new Store()
listbox.add(store)
populateAndEdit(store)
delete->click:
store = listbox.selectedItem
db.deleteOnSubmit(store)
listbox.remove(store)
db.submit()
edit->click:
populateAndEdit(listbox.selectedItem)
save->click:
parseAndSave(listbox.selectedItem)
db.submit()
disableTexts()
cancel->click:
disableTexts()
The problem is in how I determine if we are inserting a new Store, or updating an existing one.
The obvious solution to me would be to make it a "modal" process - that is, when I click edit, I go into edit mode, and the save button does things differently than if I were in add mode.
I know I could make this more MVC-like, but I don't really think this simple form merits the added complexity. I'm not very experienced with winforms, so I'm not sure if I even have the right idea for how to tackle this.
Is there a better way to do this? I would like to keep it simple, but usable.

use some type of identifier, i.e., the name of the store. Now, when the user presses Save, check to see if your collection of stores already contains one with the same name. If it does, it's an update, otherwise it is a new store.
I realize that using the name of the store may not be possible for you (i.e., a supermarket with many branches), but you get the idea.

Surely you have some kind of ID in the database? Your object would expose this primary key as a StoreID or ID property for example. If it's a GUID, it'll be Guid.Empty for a new object, if it's an auto-incrementing integer it would be zero. When you save it to the database, it should get a valid ID and then you can easily tell if the object is new or existing.

you could check some kind of unique identifier as previously mentioned, or in the framework my company uses (CSLA .NET) there is a boolean IsNew field on our objects, that when we create a new object the field is marked true. When data is read into the object from the database the IsNew field is marked as false. This gives you the ability to have some kind of use the default new constructor in all cases, then when you populate an existing item mark it false.

In your situation, you may want to look at storing more than just a simple string to the listbox. Do you have any domain objects which the listbox values represent? Add these to the listbox instead - make sure to override the .ToString() so that the listbox ends up visualizing something meaningful. When the user selects Add, create a new domain object and add it to the listbox, ensuring that the appropriate property is set to mark this as a new record for insert to the database. Conversely, any records persisted to the database, as well as all existing records fetched from the database, could be marked appropriately so that you can handle any necessary edits and deletes.

You can just play with the text of your save button, just in case if it's new store change its text to "Insert Store" and in case of edit it would be "Update Store".
add->click:
store = new Store()
listbox.add(store)
save.Text="Insert Store"
populateAndEdit(store)
delete->click:
store = listbox.selectedItem
db.deleteOnSubmit(store)
listbox.remove(store)
db.submit()
edit->click:
save.Text="Update Store"
populateAndEdit(listbox.selectedItem)
save->click:
parseAndSave(listbox.selectedItem)
if (save.Text.Equals("Insert Store"))
db.InsertOnSubmit(listbox.selectedItem)
db.submit()
disableTexts()
cancel->click:
disableTexts()
Hope this helps!

Related

WinForms: providing text editor with dynamic suggestions popup

I want to implement something like Google's search bar behavior for our application: user must be able to enter user name as free text and based on entered data system must provide a couple of suggestions on a popup bar based on already existent user names.
Here's the brief algorithm:
user enters some character to text edit box
system fires some changing event with web service call inside it that updates suggestions list data
Text edit must also provide an ability to enter and keep a free text to create new user, not just looking up for existent
I can't use devexpress's lookupeditds - they allow to keep only values, presented in datasource - even if new value has being processed inside ProcessNewValue by adding to datasource,
Changing event fires one more time with refreshing my datasource overwriting new unique value.
Now I am looking forward Combobox control. But looks like there is no ability to enter free text alongside with displaying suggestions popup.
I can't use devexpress's lookup edits - they allow to keep only values, presented in datasource - even if new value has being processed inside ProcessNewValue by adding to datasource,
I believe you're wrong here because you can use the DevExpress LookUpEdit with easy:
class AutoCompleteLookUpEdit : LookUpEdit {
List<string> suggestions = new List<string>();
public AutoCompleteLookUpEdit() {
Properties.DataSource = suggestions;
Properties.ImmediatePopup = true;
}
protected override void ProcessFindItem(KeyPressHelper helper, char pressedKey) {
suggestions.Clear();
// add search suggestions here depending on helper.Text value
suggestions.Add("google");
suggestions.Add("devexpress");
// ...
base.ProcessFindItem(helper, pressedKey);
}
}
Take a look at the How to create an editor with a dynamic autocomplete list for the detailed example.
P.S. You can use the AcceptEditorTextAsNewValue property to control whether or not lookup accepts entered text as valid value even it does not belong the underlying data source.

Is two data sources for a DataGridView.ComboBoxColumn possible?

I have a DataGridView with several TextBoxColumns and one ComboBox column called 'combo' that holds the client type. The problem is that I'd like to show both the currently selected client-type value along with the dropdown client-type list to validate future changes by the user. In SQL Server, I have a DB with two table columns, 'client_type_dropdown.name' and 'clients.client_type'. The 'client_type_dropdown.name' column is a validation list. The 'clients.client_type' column contains the current client type for clients in the database. Is there a way to show in 'combo' both 'client_type_dropdown.name' and 'clients.client_type' , i.e., one source for the ComboBoxColumn dropdown and a different source for the textbox part of 'combo'? Or do I need to have two columns in my grid?
I appreciate your help.
I'm using a third party grid, but I usually handle this by setting the combo drop down style to DropDown instead of DropDownList. This will allow your original database value to display, even if it isn't in the list.
This also allows free typing of values into the combo field, so the trick after that is to validate the user input to make sure it matches a value in the list before you allow them to save updated values. You could play around with the LimitToList property of the combo to possibly save you doing the validation manually, but with most controls I have worked with it will give you more grief than help.

Dynamically adding buttons and adding their source code

Greeting,
I have already checked for my question with no luck of an answer or something similar.
So here it's my problem:
I have created a cafe cashier software for my boss that it has buttons for each product that cashier wants to add on a bill/table. If a button is clicked, for example btnOrangeJuice, on its click event, it call a function for example named: addOrder("Orange Juice");
Inside this function it does the simple follow code:
a) it connect to the database
b) returns price of product "Orange Juice" for example (select price from products where product_name = '" + product_parameter + "'")
c) take the result, and add it to the order list box with it's price and so on..
The problem here is, (lets go with the previews example) every time we have a new product, I have to manually customize the form by adding a button 52x52 pixels, name btnOrangeJuice, text name "Orange Juice", and on the click event to call my function addOrder("Orange Juice"), then upload the new version of my software to my online web hosting, and update the software from the cashier's pc. This is time consuming for me, especially when we make new deals with suppliers so i wanted to make my program to add dynamically buttons, to do all this by just having a form, type in the button properties, calling a function, and add a button by its self with its dimensions, check if its out of form space, if it is, the add the button bellow instead on the right, and of course add the button properties and its click event (that call my built-in function).
If you need any farther details regarding my software/problem please do ask.
So can you assist me on this please?
The standard approach is to assign each product a unique identifier and have one mechanism for adding an order which takes the unique identifier as the parameter. Your products already presumably have a unique identifier as they are persisted entities (a database primary key for example).
If you wish the add button to have the text of the product, then you can dynamically set this from the product name, which is again already stored in the database. There is no need to replicate this information in your UI code.

Updating Data with LINQ and BindingSource

I am writing a relatively simple Windows Form app that is supposed to act as a front-end (adding, editing, removing entries) for a SQL Server database we have. I have a TextBox for each column in the table, and a ListBox to list all the entries (by first and last name). The TextBoxes get populated with the data of whichever entry is selected in the ListBox.
I am having some difficulty updating entries in the DB using the BindingSource. Here is the code that I am currently (unsuccessfully) using:
DBDataContext dc = new DBDataContext();
Entrys e = (Entry)EntryBindingSource.Current;
dc.Entrys.Attach(e);
dc.Entrys.InsertOnSubmit(e);
dc.SubmitChanges();
With this code I get an exception that the entry already exists, which makes sense, but I don't know how to tell it that I want to update that entry with the new data.
I know how you can manually update each entry, but since I have 10 different columns, that would be a relatively large if/else tree (checking if each textbox's value is different than the BindingSource's value for that entry). Deleting and then re-adding that entry just seems like bad form to me. I'm sure there's a better way of doing it.
I highly doubt you are doing this right.
Using Linq you should first try to retrieve your entry/check for its existence, then make your changes, and then only submit them. Updating this way should be pretty straightforward. the "InsertOnSubmit" call is in my opinion very suspicious.

handling lookup tables with deleted records and databound controls

I have a table Resource with a field Type. Type is a lookup into the table ResourceType.
So for instance ResourceType might have:
1: Books
2: Candy
3: Both
And Resource might have
1: Tom's Grocery, 2
2: Freds News, 3
It would display as: Tom's Grocery Candy
Now lets say I am using a databound combobox for the resource type and the third record is deleted from ResourceType, we of course get an error when Fred's News is displayed. I could simply put a marker in (perhaps an asterisk), indicating that it has been deleted, rather than actually delete it. It shows up as **Both* in the textbox portion of the combo and I am content.
However, I would not want it to show up as an option in the dropdown. Is this too much to ask from databound fields? Must I write my own code to load the drop down?
Add a bit Deleted column to the lookup table. When you delete a type, set Deleted = 1. When you pull back ResourceTypes, only pull out ResourceTypes where Deleted = 0 and then bind to the dropdown.
Edit:
How are you getting the dataset that you're binding to the dropdownlist? Are you using drag and drop datasets? I really haven't worked with datasets like that in years, but I'm pretty sure you can change the Get sql to what you need it to be.
OK, I already have most of that built into the solution - but I must be binding wrong. If I only pull back records where deleted = 0, I get exceptions - I'm guessing because the textbox can't be filled from the record set.
I guess I'm not sure how to bind the textbox display to one dataset - the one with all the records - and the dropdown to a filtered dataset.
Simply adding a deleted column was not enough - there had to be a way to see a deleted record in the text portion of a combo box while at the same time filtering out deleted records in the drop down.
In the end, I wrote a custom user control to handle this.

Categories