Associate a button with a passenger C# - winforms

Hi I produced a windows form. The goal is to book seats on a airplane but now i'm finding quite distressing the path that I choose - when the passenger chooses the seat graphically by pressing a button the button's color is being changed but now I need to add a piece of code that could help me save this information and associate it with the passenger.
Regards
private void button4_Click(object sender, EventArgs e)
{
this.F16.BackColor = Color.LightBlue;
this.F16.ForeColor = Color.Red;
}

If I understand right, then just create a new class Passenger, where you keep all information about passenger and choosen places by him
public class Passenger
{
public string Name { get; set; }
public string place { get; set; } // or list of places
public Passenger(String name)
{
this.Name = name;
}
public void savePlace(string newPlace)
{
this.place = newPlace;
}
}
Then in your form create a variable
private Passenger currentPassenger;
And inside of your function save a choosen place
private void button4_Click(object sender, EventArgs e)
{
this.currentPassenge.SavePlace(this.F16.name)//or just "F16"
this.F16.BackColor = Color.LightBlue;
this.F16.ForeColor = Color.Red;
}
if your have own button for every place, then better assign a place's data in .Tag property
this.button4.Tag = "F16"
if so then you need only one handler for all buttons
private void PlaceButtons_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
this.currentPassenger.savePlace((string)btn.Tag);
this.F16.BackColor = Color.LightBlue;
this.F16.ForeColor = Color.Red;
}
and ofcourse in constructor of Form add event handler to all place's buttons
this.button1.Click +=new EventHandler(PlaceButtons_Click);
this.button2.Click +=new EventHandler(PlaceButtons_Click);
this.button4.Click +=new EventHandler(PlaceButtons_Click);
Or if you want associate in other way places with passenger then create Place class
public class Place
{
public string Code{ get; set; }//code of place "F16"
public string passenger { get; set; } //Name of passenger
public Place(String passengerName)
{
this.passenger = passengerName;
}
public void SavePassenger(string newpassenger)
{
this.passenger = newpassenger;
}
}
And do the same things in event handler PlaceButtons_Click, but save passenger name in Place class. In form create a list of places or hashtable (Place; Passenger) or something else independing on using of application.

Related

Winforms, EF Core, dropdown combobox bound to BindingSource. Is there a descent way of persisting newly added items? BindingList?

I am trying to build a Patient's edit form that will get Patient data from a database using EF Core and the DbContext derived AppDbContext.
On the same form there will be a dropdown combobox that will be displaying all the available insurances (fetched from the database).
What I want to achieve is the ability, the user to be able to select an existing insurance (which is obvious and easily achieved) or to add a new one by typing it into the combobox and this new entry should be selected as the patient's insurance from now on until the SaveChanges takes place and when the same patient is reopened for editing.
I use two BindingSources one for the patient itself (bsPatient) and one for the insurances list (bsInsurances).
I have the following two models (1:many relationship)
public class Insurance
{
public int Id { get; set; }
public string Name { get; set; } = String.Empty;
public virtual ObservableCollectionListSource<Person> Persons { get; } = new();
}
public class Person
{
public int Id { get; set; }
public string LastName { get; set; } = String.Empty;
public string FirstName { get; set; } = String.Empty;
public DateTime DOB { get; set; }
public int InsuranceId { get; set; }
public Insurance Insurance { get; set; } = null;
}
And this is the DbContext:
public class AppDbContext : DbContext
{
private const string DatabaseFileName = "MyPatientsDB.sqlite3";
public DbSet<Person> Persons { get; set; }
public DbSet<Insurance> Insurances { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder
.UseSqlite(#$"Data Source={DatabaseFileName}");
On the form there will be
public partial class PatientForm : Form
{
private AppDbContext _db = new();
private int _patientId = 0;
ObservableCollection<Insurance> _insurancesList = new();
public PatientForm(int patientId)
{
InitializeComponent();
_patientId = patientId;
}
protected async override void OnLoad(EventArgs e)
{
base.OnLoad(e);
await _db.Insurances.LoadAsync();
_insurancesList = new ObservableCollection<Insurance>(_db.Insurances.Local);
bsInsurances.DataSource = _insurancesList;
bsPatient.DataSource = await _db.Persons.FirstOrDefaultAsync(p => p.Id == _patientId);
}
protected async override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
bsInsurances.EndEdit();
if (cbInsurances.FindStringExact(cbInsurances.Text) == -1)
{
var newInsurance = new Insurance { Id = 0, Name = cbInsurances.Text };
_db.Insurances.Local.Add(newInsurance);
}
bsPatient.EndEdit();
await _db.SaveChangesAsync();
_db?.Dispose();
}
}
So far, I am able to save correctly the Insurance selection of the combobox when an already existing item is selected. The problem arises when the user inserts a new insurance entry into the combo textbox. This new entry can not be saved to the db and be displayed the next time the same patient is opened for editing.
I would be grateful if someone could point me towards which direction to follow to achieve this. I mean, while editing a patient's data how to be able to insert a new entry into the insurances combo and this new entry to be persisted into the db and be displayed and selected the next time the patient is opened for editing.
I think I've found a solution. I don't know if it is the best one but it seems to be working at least into my project. I am just referring it in case someone else has the same query.
Please if anyone has a better solution I would be grateful for his/her help.
protected async override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
bsInsurances.EndEdit();
if (cbInsurances.FindStringExact(cbInsurances.Text) == -1)
{
if (bsPatient != null && bsPatient.DataSource != null)
{
(bsPatient.DataSource as Person).Insurance = new Insurance() { Name = cbInsurances.Text as string };
}
}
bsPatient.EndEdit();
await _db.SaveChangesAsync();
_db?.Dispose();
}

How can I raise a GUI event in WCF?

Suppose, I want to add a button in a WinForms WCF client such that, whenever a user pushes the button, a specific client on the other side would see a MessageBox saying Hello [user].
I have modified this program to have a DataGridView instead of the big TextBox. I also tried to raise the event up on double click of a DataGridView row.
I have done something like the following:
[ServiceContract(SessionMode = SessionMode.Allowed)]
public interface ICallableForm
{
[OperationContract]
void ShowMessage();
}
[DataContract]
public class ChatUser
{
//...
[DataMember]
public ICallableForm WinForm { get; set; }
public override string ToString()
{
return this.Username;
}
}
class MainForm : Form, ICallableForm
{
// ...
public void ShowMessage()
{
MessageBox.Show("Hello " + ___clientUser.Username);
}
// ...
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
int rowIndex = e.RowIndex;
ChatMessage message = dataGridView1.Rows[rowIndex+1].Tag as ChatMessage;
ChatUser user = message.User;
ICallableForm form = user.WinForm;
form.ShowMessage();
string str = string.Empty;
}
And, getting the following error:

WPF Datagrid get data on CheckboxChecked-Event

I've got a datagrid with a checkbox, name and email.
On CheckboxChecked I want to copy the email into another list or string.
How do I get the specific value from the checked row?
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
object row = lbxCC1.SelectedItem;
int columnIndex = lbxCC1.Columns.Single(c => c.Header.Equals("eMail")).DisplayIndex;
String eMail = (lbxCC1.SelectedCells[columnIndex].Column.GetCellContent(row) as TextBlock).Text;
MessageBox.Show(eMail);
}
Edit (09.09.2016):
Maybe I should show you a bit more code.
public class Person
{
public string Nachname { get; set; }
public string Vorname { get; set; }
public string eMail { get; set; }
public string Abteilung { get; set; }
}
public static class PersonService
{
public static List<Person> ReadFile(string filepath)
{
var lines = File.ReadAllLines(filepath);
var data = from l in lines.Skip(1)
let split = l.Split(';')
select new Person
{
Nachname = split[1],
Vorname = split[2],
eMail = split[31],
Abteilung = split[4],
};
return data.ToList();
}
}
I call it with:
lbxCC1.DataContext = PersonService.ReadFile(#"C:\Test.csv");
As I'm building the columns from code behind, I guess I have to bind them aswell am I right?
Sorry for this, but I'm new to datagrids :-)
I think this might help you:
Dim row As Data.DataRowView = DirectCast([yourDataGrid].SelectedItems(rowIndex), Data.DataRowView)
Then in your CheckBox_Checked Event:
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
MessageBox.Show(row("email"); 'Assuming the column name is email
}
This is IF your values are data-bound to the DataGrid.

DataGridViewColumn.DataPropertyName Property

I have a DataGridView control and I want to populate it with data.
I use DataSource property
// dgvDealAsset is DataGridView
private void DealAssetListControl_Load(object sender, EventArgs e)
{
dgvDealAssets.AutoGenerateColumns = false;
dgvDealAssets.DataSource = DealAssetList.Instance.Values.ToList();
}
Now problem number one. The class of my collection does not contain only simple types that I can map to columns using DataPropertyName. This is the class that is contained in collection.
class MyClass
{
public String Name;
MyOtherClass otherclass;
}
class MyOtherClass
{
public String Name;
}
Now I am binding properties of MyClass to columns
col1.DataPropertyName = "Name" // Ok
col2.DataPropertyName = "otherclass" // Not OK - I will have empty cell
The problem is that I want to display otherclass.Name field. But if I try to write
col2.DataPropertyName = "otherclass.Name"
I get empty cell.
I tried to manually set the column
private void DealAssetListControl_Load(object sender, EventArgs e)
{
dgvDealAssets.AutoGenerateColumns = false;
dgvDealAssets.DataSource = DealAssetList.Instance.Values.ToList();
// iterate through rows and set the column manually
foreach (DataGridViewRow row in dgvDealAssets.Rows)
{
row.Cells["Column2"].Value = ((DealAsset)row.DataBoundItem).otherclass.Name;
}
But this foreach cycle takes about minute to complete (2k elements). How to solve this problem?
DataGridView doesn't support databinding to child properties. For more info, check this post
I like the solution that uses the CellFormatting event.
Problem nr.1:
Try to do the following:
extend MyOtherClass from Object (this step might not be needed)
and override, or create, method ToString().
That should do it.
In case you want to use many child elements like this:
class MyClass
{
public int Id;
public MyOtherClass OtherClass;
}
class MyOtherClass
{
public string Name;
public int Number;
}
How about
1st solution
Set value for each cell in some event (mabye other one is better), manually, after setting datasource, for example:
private void dgv_CellFormatting( object sender, DataGridViewCellFormattingEventArgs e )
{
MyClass data = dgv.Rows[ e.RowIndex ].DataBoundItem as MyClass;
dgv.Rows[ e.RowIndex ].Cells[ "colName" ].Value = data.OtherClass.Name;
dgv.Rows[ e.RowIndex ].Cells[ "colNumber" ].Value = data.OtherClass.Number;
}
2nd solution
What about creating a DataTable from the data and then bind it?
I'd be thankful for any opinion ;-)
It sounds like the DataGridView's virtual mode would solve your problem. In virtual mode, the DataGridView will fire an event whenever it needs to display a cell. The event lets you populate the cell however you please. The advantage of virtual mode is the system only needs to pull the data that's actually being displayed, so there's no slow start-up time while you load everything.
private void my_init_function() {
datagridview.VirtualMode = true;
datagridview.CellValueNeeded += new System.Windows.Forms.DataGridViewCellValueEventHandler(datagridview_CellValueNeeded);
}
private void datagridview_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
e.Value = get_my_data(e.RowIndex, e.ColumnIndex);
}
The way of databinding a specific column of a datagrid to a child property of the datagrid's datasource is using the DataGridView.Column.Tag property, along with the ToString() override method inside the child object. It goes as follows:
public class Car
{
public int Id { get; set; }
public int Name { get; set; }
public string Colour { get; set; }
public Wheel Wheel { get; set; }
}
public class Wheel
{
public string WheelName { get; set; }
public override string ToString()
{
return WheelName;
}
}
public class Main
{
private void LoadGrid(List<Car> data)
{
this.dataGridView.Columns["Wheel"].Tag = "WheelName";
}
}

Silverlight child windows in MVVM pattern

I am trying to find the right way to get the data from a ChildWindow/popup using a MVVM pattern in Silverlight (3). For example: I have a main page with a data entry form and I want to open a popup with a list of customers. When user selects a customer I want to transfer selected customer into the main page. This is what the (example) code which I am using at the moment:
Main page
public partial class MainPage : UserControl
{
public MainPageViewModel ViewModel { get; private set; }
public MainPage()
{
InitializeComponent();
ViewModel = new MainPageViewModel();
DataContext = ViewModel;
}
private void SearchCustomer_Click(object sender, RoutedEventArgs e)
{
ViewModel.SearchCustomer();
}
}
public class MainPageViewModel: ViewModel
{
private string customer;
public string Customer
{
get { return customer; }
set { customer = value; RaisePropertyChanged("Customer"); }
}
public void SearchCustomer()
{
// Called from a view
SearchWindow searchWindow = new SearchWindow();
searchWindow.Closed += (sender, e) =>
{
if ((bool)searchWindow.DialogResult)
{
Customer = searchWindow.ViewModel.SelectedCustomer.ToString();
}
};
searchWindow.Show();
}
}
Child window
public partial class SearchWindow : ChildWindow
{
public SearchWindowViewModel ViewModel { get; private set; }
public SearchWindow()
{
InitializeComponent();
ViewModel = new SearchWindowViewModel();
DataContext = ViewModel;
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = ViewModel.OkButtonClick();
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = ViewModel.CancelButtonClick();
}
}
public class SearchWindowViewModel: ViewModel
{
private Customer selectedCustomer;
private ObservableCollection<Customer> customers;
public ObservableCollection<Customer> Customers
{
get { return customers; }
set {customers = value; RaisePropertyChanged("Customers"); }
}
public Customer SelectedCustomer
{
get { return selectedCustomer; }
set { selectedCustomer = value; RaisePropertyChanged("SelectedCustomer"); }
}
public SearchWindowViewModel()
{
Customers = new ObservableCollection<Customer>();
ISearchService searchService = new FakeSearchService();
foreach (Customer customer in searchService.FindCustomers("dummy"))
Customers.Add(customer);
}
public bool? OkButtonClick()
{
if (SelectedCustomer != null)
return true;
else
return null; // show some error message before that
}
public bool? CancelButtonClick()
{
return false;
}
}
Is this the right way or is there anything more "simple"?
Cheers,
Rok
More problematic here is the use of View specific terms and types in your VMs. Click events, DialogResults should not be anywhere near your ViewModels.
With regards to the question, I had a similiar question about this here:
Handling Dialogs in WPF with MVVM
The answer I accepted was the use of the Mediator pattern to get around this. Have a look. :)
A good MVVM library which supports opening child window is Chinch mvvm helper library. You can look at a sample at http://www.codeproject.com/KB/silverlight/SL4FileUploadAnd_SL4_MVVM.aspx.

Resources