I have a class that has the following syntax:-
public class CorporateTeamTimeSheetTotalsForSpecifiedTimeFrame
{
private List<EmployeeMini> _EmployeesList = new List<EmployeeMini>();
private List<HolidayCalendar> _Holidays = new List<HolidayCalendar>();
public List<EmployeeMini> EmployeeList
{
get { return _EmployeesList; }
set { _EmployeesList = value; }
}
}
Now I want to access these holidays in individual employee mini i.e. for individual employee.
How can i do that?
Regards
Abhishek
This code clearly does not show any relationship between Employees and Holidays. You may simplify this further by associating each EmployeeMini with HolidaysList and then creating a list of EmployeeMini, as:
public class EmployeeMini
{
// ...
private List<HolidayCalendar> _Holidays = new List<HolidayCalendar>();
// ...
}
public class CorporateTeamTimeSheetTotalsForSpecifiedTimeFrame
{
private List<EmployeeMini> _EmployeesList = new List<EmployeeMini>();
public List<EmployeeMini> EmployeeList
{
get { return _EmployeesList; }
set { _EmployeesList = value; }
}
}
Assuming _Holidays is a list of employee holidays and not company holidays.
Please take this solution as a starting point and not as a copy-paste solution.
Edit:
If data of holidays is same for all employees, you may create a separate entity Holidays. You do not have to associate this with the employees. This seems to be a TimeSheet application.
You may associate time entries with Employees, Tasks (which is generally the case) and Holidays.
Related
I'm trying to use the MVVM pattern in C#. Therefore I have a customer class:
public class Customer
{
public string CustumerNumber { get; set; }
public string CustomerName { get; set; }
}
I fill a list with Customers from a database:
public class CustomerList
{
public static List<Customer> customerlist = new List<Customer>();
public static List<Customer> GetCustomer()
{
// Get data from database
}
}
My ViewModel:
class ViewModel : BaseViewModel
{
public ObservableCollection<Customer> Customers { get; set; }
public string CustomerSearch { get; set; }
public ViewModel()
{
Customers = new ObservableColletion<Customers>(CustomerList.GetCustomer());
}
}
I bound Customers in an WPF-ListBox:
<ListBox ItemsSource="{Binding Customers}"
DisplayMemberPath="CustomerName"/>
Let's say I have 10 objects of CustomerName in the ListBox. There is a TextBox that contains a string. Now I want to remove all objects in the ListBox that don't contain the string. I solved the problem in the ViewModel as follows:
public void SearchCustomer()
{
foreach (Customer item in Customers)
{
if (item.Customers.ToUpper().Contains(CustomerSearch.ToUpper()) == false)
{
this.Customers = new ObservableCollection<Customer>(CustomerList.RemoveItemsFromView(item));
}
}
}
Is this right? It feels wrong to me, because every time the loop removes an item I create a new ObservableCollection instead of manipulating the existing one. Is there a more professional way to solve this task?
For the PropertyChangeEvent I use FodyWeaver
If you don't want to create a new source collection, you could remove items from the existing one. Just make sure that you don't call the Remove method in a foreach loop.
This should work:
for (int i = Customers.Count - 1; i >= 0; i--)
{
Customer item = Customers[i];
if (item.Customers.ToUpper().Contains(CustomerSearch.ToUpper()) == false)
{
Customers.RemoveAt(i);
}
}
If you do reset the collection property each time you want to add or remove an item, you might as well use a List<T>. Just make sure that you raise a property notification when the property is set.
Since you already have the Customer item you can just do this inside your if:
this.Customers.Remove(item)
You should use the method Remove from Customers like you are doing with CustomerList. Or update Customers after the loop:
First Option
foreach (Customer customer in Customers)
{
if (!customer.Customers.ToUpper().Contains(CustomerSearch.ToUpper()))
{
CustomerList.RemoveItemsFromView(customer);
Customers.Remove(customer);
}
}
Second Option
foreach (Customer customer in Customers)
{
if (!customer.Customers.ToUpper().Contains(CustomerSearch.ToUpper()))
{
CustomerList.RemoveItemsFromView(customer);
}
}
this.Customers = new ObservableCollection<Customer>(CustomerList);
I can't suggest you more options without havig CustomerList and RemoveItemsFromView source code.
Also, I refactored a bit the code. Having a good name for variables is important. And if looks a bit wrong, but I don't have your model.
Assume I have following Model structure:
class Team {
public string Name {get;set; }
public List<Player> players {get;set;}
}
class Player {
public int Age {get;set;}
public string Name {get;set;}
public Team Team {get;set;}
}
I wish to create Viewmodels for this model. However, I also would like to avoid duplicating all properties from Player in the TeamVM and vice versa (for this simple example this would be feasable, but in reality rather cumbersome).
Looking at the literature and online articles, it seems that the "Pure" way would be to create a ViewModel for each Model and to have a ViewModel only return other ViewModels and never Models. This is all fine, but my problem is: how do you create these viewmodels without getting into a recursion trap. Assume I do it like this:
public class TeamVM: ViewModel<Team> {
private ObservableCollection<PlayerVM> _players;
public TeamVM(Team t): base(t) {
_players = new ObservableCollection();
foreach (Player p in t.players) {
_players.Add(new PlayerVM(t));
}
}
public string Name {
get { return _modelElement.Name; }
set { _modelElement.Name = value; NotifyPropertyChanged(); }
}
public ObservableCollection<PlayerVM> Players {
get { return _players; }
}
}
and
public class PlayerVM : ViewModel<Player> {
private TeamVM _teamVM;
public PlayerVM(Player p): base(p) {
_teamVm = new TeamVM(p.Team);
}
public int Age {
get { return _modelElement.Age; }
set { _modelElement.Age = value; NotifyPropertyChanged(); }
}
public string Name {
get { return _modelElement.Name; }
set { _modelElement.Name = value; NotifyPropertyChanged(); }
}
public TeamVM Team {
get { return _teamVM; }
set { _teamVm = value; NotifyPropertyChanged(); }
}
}
Obviously, the above can never work, since it creates recursion: creation of a TeamVM results in the creation of PlayerVMs which in turn spawn TeamVMs again etc.
Right now, I have solved this, by adding an intermediate class as follows:
public class TeamMinimalVM: ViewModel<Team> {
public TeamVM(Team t): base(t) {
}
public string Name {
get { return _modelElement.Name; }
set { _modelElement.Name = value; NotifyPropertyChanged(); }
}
}
public class TeamVM: TeamMinimalVM {
private ObservableCollection<PlayerVM> _players;
public TeamVM(Team t): base(t) {
_players = new ObservableCollection();
foreach (Player p in t.players) {
_players.Add(new PlayerVM(t));
}
}
}
And then having PlayerVM depend on TeamMinimalVM instead of TeamVM. This means that in the views, you would be able to do: {Binding Player.Team.Name} but not {Binding Player.Team.Players.Name}, which is kind of ok for me I guess since I don't think it's a great idea to do this anyway.
My question now is: is there a better/more "standard" way to do "Pure" VMs of bidirectional model elements? I do not want to clone properties of one type in the other (there are too many), nor do I want to expose Model elements directly.
Finally, the ViewModel class I use is this one (just for completeness, but it is not essential to the question I think.)
public class ModelElementViewModel<T> : ObservableObject where T : class
{
private bool _modelElementChanged;
private T _modelElement;
public ModelElementViewModel(T element)
{
_modelElement = element;
}
/// <summary>
/// The underlying model element for this viewmodel. Protected as one should not bind directly to model elements from the gui.
/// </summary>
internal T ModelElement {
get { return _modelElement; }
set {
if (_modelElement != value)
{
_modelElement = value;
ModelElementChanged = false;
NotifyAllPropertiesChanged();
}
; }
}
/// <summary>
/// Property that can be used to see if the underlying modelelement was changed through this viewmodel (note that an external
/// change to the model element is not tracked!)
/// </summary>
public bool ModelElementChanged {
private set
{
if (_modelElementChanged != value)
{
_modelElementChanged = value;
NotifyPropertyChanged();
}
}
get
{
return _modelElementChanged;
}
}
protected override void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
ModelElementChanged = true;
base.NotifyPropertyChanged(propertyName);
}
}
Edit:
What wasn't clear from my original question is that Players are not used exclusively by teams. I want following three scenarios to work:
I want to be able to create a view for a single player that displays all player information
I want to be able to create a view for a team, displaying the information of that team and a table of all players with their statistics
I also want to be able, for example, to have a Playersbook view, which consists of a table displaying all known players with their teamname for example.
Your classes have a clear hierarchy: teams aggregate players. Teams are owners, players are owned. Therefore, when creating a player VM, you can pass team VM as a constructor argument.
The obvious limitation of this is now you can't have players without teams. Possible solutions are: enforcing players to always be owned by some team; supporting null as a team VM and setting a proper value later; creating a "null team" object and using it for team-less players.
In cases like these, when there's a clear aggregation hierarchy, I use my OwnedObservableCollection<T, TOwner>. With it, I can create create a collection _players = new OwnedObservableCollection<PlayerVM, TeamVM>(this) in a team, then just add and remove players to and from the teams by using just Add and Remove.
I need to Create a Class and Property dynamically from database table (Employee).
I need to Create a class and property at runtime and assign value to property
for example
public class Employee
{
private int _Id;
public int Id
{
get { return _Id; }
set { _Id = value; }
}
private String _Code;
public String Code
{
get { return _Code; }
set { _Code = value; }
}
}
Then I need to access this class on object
List<Employee> objlstEmp = new List<Employee>();
Employee objEmp = new Employee();
objEmp.Id = 1;
objEmp.Code = "Emp01";
objlstEmp.Add(objEmp);
As others commented, from your example looks like you don't need to generate classes at runtime, but use an ORM framework and do that design time.
As it seems the topic is unfamiliar to you, I would recommend looking into Entity Framework and because you already have a DB, generate the model from that. Look up how to create the model from DB.
first of all congrats for the web, this is my first question but I have found a lot of answer before here.
Here my problem: I have to take some data from an excel file and print them off in a file. Until here everything is ok. But depending on the order of the file list, I take the data in one or another order. My proposal is after all the data have been taken from the excel, to sort those data by the date of the bill (one of the elements of the data). I am describing my classes below.
I have my Bill class:
class Bill
{
private string billNumber;
private string billDate;
private DateTime date;
private string from;
private string to;
private string billCost;
private string power1;
private string power2;
private string power3;
private string power4;
private string power5;
private string power6;
private string contractNumber;
}
And this is my Contract Class:
class Contract
{
private List<Bill> billList;
private Dictionary<double, Bill> billsDictionary;
private double contractNumber;
}
After in my program I have a List<Contract>.
I would like to sort the List<Bill> of the Contract class by the date, to be able to print the bill in the correct order, but I have not been able to find any solution to order them.
Thanks in advance.
Greetings.
There are two solutions. First you need to expose property that can be used to sort.
public class Bill
{
// ... rest of your code
public DateTime Date
{
get
{
return this.date;
}
}
}
1) You can use List's Sort with passed comparer (msdn):
public class Comp : IComparer<Bill>
{
public int Compare(Bill x, Bill y)
{
// remember to handle null values first (x or y or both are nulls)
return x.Date.CompareTo(y.Date);
}
}
then:
billList.Sort(new Comp());
Keep in mind: if you declare Comp as nested class of Bill you won't have to add property Date. You will be able to see private fields of Bill and use it for comparsion..
2) You can use linq (it creates new instance of List):
billList = billList.OrderBy(bill => bill.Date).ToList();
You should be able to do that using linq like q = q.OrderBy(a => a.ColumnName) but you may want to check the access modifiers of your properties, being private you won't be able to access them from the outside.
Here's a simple example on ordering with Linq:
class Pet
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void OrderByEx1()
{
Pet[] pets = { new Pet { Name="Barley", Age=8 },
new Pet { Name="Boots", Age=4 },
new Pet { Name="Whiskers", Age=1 } };
IEnumerable<Pet> query = pets.OrderBy(pet => pet.Age);
foreach (Pet pet in query)
{
Console.WriteLine("{0} - {1}", pet.Name, pet.Age);
}
}
/*
This code produces the following output:
Whiskers - 1
Boots - 4
Barley - 8
*/
Notice how the properties of the class are public so you can access them from anywhere in the code.
More info on sorting can be found here.
It's a pleasure to see how much knowledge people have on here, it's a treasure of a place.
I've seen myself writing code for DataGridView events - and using DataSource to a backend prepared DataTable object.
Sometimes the user can remove rows, update them etc. and the underlying data will need validation checks again.
Let's assume we have a person class
class Person {
public string FirstName { get; set; }
}
Let's say some other part of the code deals with creating an array of Person.
class Processor {
public static Person[] Create()
{
....
....
return person[];
}
}
And this information would appear on a DataGridView for user viewing.
I've tried something like this:
public static DataTable ToTable(List<Person> list)
{ ... }
And had this method in the Person class .. which I would think it'd belong to. Then I would bind the DataGridView to that DataTable and the user will then see that data and do their tasks.
But I've thought of using BindingList<> which I'm not so educated on yet.. would I still have the same capability of sorting the DataGridView like it does with DataTable as a DataSource? Would BindingList be implemented by a container class like "PersonCollection" or would the Person class implement itself? I would like to fire some events to be able to modify the collection in a clean way without having to reset datasources, etc. Where the user experience could really be affected.
I understand that modifying the DataSource DataTable is the good way. But sometimes I need to fire methods in the corresponding class that that specific row refers to, and had an ugly extra hidden column which would hold a reference to the existing object somewhere else (the Person reference).
If you guys know a better design solution, I would be more than happy to hear it.
Thanks in advance,
PS. After reading "The Pragmatic Programmer", I just can't stop thinking critically about code!
Leo B.
Create a business object class. Implement INotifyPropertyChanged. Look at the code below:
public class Employee:INotifyPropertyChanged
{
public Employee(string Name_, string Designation_, DateTime BirthDate_)
{
this.Name = Name_;
this.Designation = Designation_;
this.BirthDate = BirthDate_;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
[DisplayName("Employee Name")]
public string Name
{
get { return this._Name; }
set
{
if (value != this._Name)
{
this._Name = value;
NotifyPropertyChanged("Name");
}
}
}
private string _Name = string.Empty;
[DisplayName("Employee Designation")]
public string Designation
{
get { return this._Designation; }
set
{
if (value != this._Designation)
{
this._Designation = value;
NotifyPropertyChanged("Designation");
}
}
}
private string _Designation = string.Empty;
public DateTime BirthDate
{
get { return this._BirthDate; }
set
{
if (value != this._BirthDate)
{
this._BirthDate = value;
NotifyPropertyChanged("BirthDate");
}
}
}
private DateTime _BirthDate = DateTime.Today;
[DisplayName("Age")]
public int Age
{
get
{
return DateTime.Today.Year - this.BirthDate.Year;
}
}
}
Create your custom collection:
public class EmployeeCollection:BindingList<Employee>
{
public new void Add(Employee emp)
{
base.Add(emp);
}
public void SaveToDB()
{
//code to save to db
}
}
Set the data source:
_employeeStore = new EmployeeCollection();
this.dataGridView1.DataBindings.Add("DataSource", this, "EmployeeStore");
Now if you want to add an employee to your datagridview,
Employee employee = new Employee(textBoxName.Text, textBoxDesignation.Text, dateTimePicker1.Value);
_employeeStore.Add(employee);
This is very clean. You just play with business object and don't touch the UI.
Havent read you question fully, bbut you might want to take a look at my Project ModelShredder, which provides a convinient and fast ToDataTable method