MVVM Dapper how to save changed collectionitems instantly to database - wpf

I've got a question relating the above mentioned topic.
------Using Dapper and Caliburn Micro-----
At the moment im building a mvvm wpf application which displays a list of orders. These orders need some ressources to be allocated so the workprocess can begin.
The list of orders provide a few buttons for each row (order) to start, pause, finish and to set the status of the order like "is material allocated".
Whats a good practise to save changes of the above steps made via the list to database?
When creating the order I simply pass the values via a buttonclick to a method in database access project.
For the moment lets just talk about the UIOrderModel and the property IsAllocated
Once the Button (the ugly beige one) is clicked the following method fires:
public void MatAllocated(UIOrderModel order) {
order.IsMatAllocated = "Y";
order.IsAllocated = true;
order.StatusFlag = MKDataWork.Library.Enums.StatusFlag.allocated;
OrdersBc.Refresh();
}
Since it's workig so far as it should be I'm on the question how to store the Information about the changed status of Allocation in my database. By way of example it would be kinda easy just to fire an update query (sp) in the method above.
The collection and the database should always have the same state of data.
The UiOrderModel:
public class UIOrderModel {
private UIOrderModel UIorder = null;
public int Code { get; set; }
public UIuserModel OrderedByEmp { get; set; }
public int OrderedByEmpPersId { get; set; }
public string OrderedByEmpName { get; set; }
public List<UIAllocationModel> AllocationList {get;set;}
public DateTime OrderDate { get; set; }
public UIDepartmentModel ForDepartment { get; set; }
public string DepartmentName { get; set; }
public DateTime ExpectedFinishDate { get; set; }
public string Project { get; set; }
public string Commission { get; set; }
public string IsMatAllocated { get; set; } = "N";
public bool IsAllocated { get; set; } = false;
public string Additions { get; set; }
public StatusFlag StatusFlag { get; set; }
public decimal? Quantity { get; set; }
public UnitOfMeasures Unit { get; set; }
public UIitemModel Item { get; set; }
public string ItemName { get; set; }
public string ItemCode { get; set; }
public DateTime FinishedDateTime { get; set; }
public UIuserModel FinishedByEmp { get; set; }
public UIOrderModel() { }
public UIOrderModel(Dictionary<string,object> entries) {
int i = 0;
this.UIorder = this;
this.Code = int.TryParse(entries["Code"].ToString(), out i) ? i : 0;
this.OrderedByEmp = (UIuserModel)entries["OrderedByEmp"];
this.OrderedByEmpPersId = ((UIuserModel)entries["OrderedByEmp"]).PersId;
this.ForDepartment = (UIDepartmentModel)entries["SelectedDepartment"];
this.DepartmentName = ((UIDepartmentModel)entries["SelectedDepartment"]).Bezeichnung;
this.ExpectedFinishDate = (DateTime)entries["ExpectedFinishDate"];
this.Quantity = (decimal?)entries["Quantity"];
this.Unit = (UnitOfMeasures)entries["SelectedUnitOfMeasures"];
this.Item = (UIitemModel)entries["Item"];
this.ItemName = ((UIitemModel)entries["Item"]).ItemName;
this.ItemCode = ((UIitemModel)entries["Item"]).ItemCode;
this.StatusFlag = (StatusFlag)entries["StatusFlag"];
this.Project = (string)entries["Project"];
this.Commission = (string)entries["Commission"];
this.Additions = (string)entries["Additions"];
}
public UIOrderModel(int code,string orderedByEmpName, int orderedByEmpPersId, string departmentName, DateTime expectedFinishDate,
decimal? quantity, UnitOfMeasures unit, string itemname, string itemcode, string project, string commission,
StatusFlag statusFlag, string additions)
{
this.UIorder = this;
this.Code = code;
this.OrderedByEmpPersId = orderedByEmpPersId;
this.OrderedByEmpName = orderedByEmpName;
this.DepartmentName = departmentName;
this.ExpectedFinishDate = expectedFinishDate;
this.Quantity = quantity;
this.Unit = unit;
this.ItemName = itemname;
this.StatusFlag = statusFlag;
this.Project = project;
this.Commission = commission;
this.Additions = additions;
}
public void SaveOrder() {
OrderModel result = (OrderModel)this;
result.SaveOrder();
}
public static explicit operator OrderModel(UIOrderModel uiOrder) {
return new OrderModel()
{
Code = uiOrder.Code,
OrderDate = uiOrder.OrderDate,
OrderedByEmp = (UserModel)uiOrder.OrderedByEmp,
OrderedByEmpName = $"{uiOrder.OrderedByEmp.FirstName} {uiOrder.OrderedByEmp.LastName}",
ExpectedFinishDate = uiOrder.ExpectedFinishDate,
ForDepartment = (DepartmentModel)uiOrder.ForDepartment,
AllocationList = uiOrder.AllocationList?.Select(am => (AllocationModel)am).ToList(),
IsMatAllocated = uiOrder.IsMatAllocated,
Quantity = uiOrder.Quantity,
Unit = uiOrder.Unit,
Item = (ItemModel)uiOrder.Item,
ItemCode = uiOrder.Item.ItemCode,
ItemName = uiOrder.Item.ItemName,
Project = uiOrder.Project,
Commission = uiOrder.Commission,
StatusFlag = uiOrder.StatusFlag,
Additions = uiOrder.Additions
};
}
public static explicit operator UIOrderModel(OrderModel order) {
return new UIOrderModel()
{
Code = order.Code,
OrderDate = order.OrderDate,
OrderedByEmp = (UIuserModel)order.OrderedByEmp,
OrderedByEmpName = $"{order.OrderedByEmp.FirstName} {order.OrderedByEmp.LastName}",
ExpectedFinishDate = order.ExpectedFinishDate,
ForDepartment = (UIDepartmentModel)order.ForDepartment,
AllocationList = order.AllocationList?.Select(am => (UIAllocationModel)am).ToList(),
IsMatAllocated = order.IsMatAllocated,
Quantity = order.Quantity,
Unit = order.Unit,
Item = (UIitemModel)order.Item,
ItemCode = order.ItemCode,
ItemName = order.ItemName,
Project = order.Project,
Commission = order.Commission,
StatusFlag = order.StatusFlag,
Additions = order.Additions
};
}
}
But whats the correct MVVM way to accomplish this in a proper manner?
Thanks for an advice!

Well I've been on vacation, returned and had some time and distance to the question above. Yesterday I chose a kinda simple way to solve it.
I've implemented the command pattern and passed the execution through my UI project to the data access. It's just one query for all kinds of statussteps (and the relating table) and updates of the whole order. Therefore I pass an enum value (action), orderNo and Id of the employee as parameter for the method / query.
I'm not completely sure if it's the best mvvm way but its working in a comfortable and fast way.

Related

Pass parameters to report Devexpress

Please tell me. Created 2 classes (Data Model)
public class User
{
public int UserID { get; set; }
public string UserName { get; set; }
public string Department { get; set; }
public int Office { get; set; }
public string Position { get; set; }
public string Phone { get; set; }
public float Mobile { get; set; }
public string EMail { get; set; }
public string Login { get; set; }
public int idArm { get; set; }
}
and
public class arm
{
public int id { get; set; }
public string name { get; set; }
public string Detalis { get; set; }
}
I installed 2 GridControlls on the form
And through DataSet showed data
string connectionString = ConfigurationManager.ConnectionStrings["connectionSIPiT"].ConnectionString;
string command = "SELECT * FROM Users";
string command2 = "SELECT * FROM arm";
sqlConnection = new SqlConnection(connectionString);
SqlDataAdapter adapter = new SqlDataAdapter(command2, sqlConnection);
SqlDataAdapter adapter1 = new SqlDataAdapter(command, sqlConnection);
DataSet dataset1 = new DataSet();
adapter.Fill(dataset1, "arm");
adapter1.Fill(dataset1, "Users");
DataColumn keyColumn = dataset1.Tables[0].Columns[0];
DataColumn foreignKeyColumn = dataset1.Tables[1].Columns[9];
dataset1.Relations.Add("armUsers", keyColumn, foreignKeyColumn);
armBindingSource.DataSource = dataset1;
armBindingSource.DataMember = "arm";
userBindingSource.DataSource = armBindingSource;
userBindingSource.DataMember = "armUsers";
gridControl1.DataSource = userBindingSource;
gridControl2.DataSource = armBindingSource;
How do I select a row in the main table GridControll. Send report data. Or pass the id of the main table to build the report? Can anyone come across such a task?
Make sure that the Modifiers property for the report parameter is set to Public or Internal
Use the GridView.GetRowCellValue method to get the ID column value of the focused record
The following assumes that you have a report called MyReport and it has a parameter called MyParameter.
var id = Convert.ToInt32(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, gridView1.Columns["UserID"]));
var rpt = new MyNewReport();
rpt.MyParameter.Value = id; //Make sure the MyParameter's Modifiers property is set to Public or Internal.

Entity Framework Core - Very slow performance

I have the following entities (I'll show the properties I'm working with because I don't want to make it larger than needed):
PROPERTY: Where a property can be child of another one and has a 1-1 relationship with GeoLocation and can have multiple Multimedia and Operation
public partial class Property
{
public Property()
{
InverseParent = new HashSet<Property>();
Multimedia = new HashSet<Multimedia>();
Operation = new HashSet<Operation>();
}
public long Id { get; set; }
public string GeneratedTitle { get; set; }
public string Url { get; set; }
public DateTime? DatePublished { get; set; }
public byte StatusCode { get; set; }
public byte Domain { get; set; }
public long? ParentId { get; set; }
public virtual Property Parent { get; set; }
public virtual GeoLocation GeoLocation { get; set; }
public virtual ICollection<Property> InverseParent { get; set; }
public virtual ICollection<Multimedia> Multimedia { get; set; }
public virtual ICollection<Operation> Operation { get; set; }
}
GEOLOCATION: As mentioned, it has a 1-1 relationship with Property
public partial class GeoLocation
{
public int Id { get; set; }
public double? Latitude { get; set; }
public double? Longitude { get; set; }
public long? PropertyId { get; set; }
public virtual Property Property { get; set; }
}
MULTIMEDIA: it can hold multiple Images, with different sizes, for a single Property. The detail here is that Order specifies the order of the images to be shown in the client application, but it doesn't start always with 1. There're some cases where a Property has Multimedia files that starts with 3 or x.
public partial class Multimedia
{
public long Id { get; set; }
public long? Order { get; set; }
public string Resize360x266 { get; set; }
public long? PropertyId { get; set; }
public virtual Property Property { get; set; }
}
OPERATIONS: defines all the operations a Property can have, using OperationType to name this operation. (rent, sell, etc.)
public partial class Operation
{
public Operation()
{
Price = new HashSet<Price>();
}
public long Id { get; set; }
public long? OperationTypeId { get; set; }
public long? PropertyId { get; set; }
public virtual OperationType OperationType { get; set; }
public virtual Property Property { get; set; }
public virtual ICollection<Price> Price { get; set; }
}
public partial class OperationType
{
public OperationType()
{
Operation = new HashSet<Operation>();
}
public long Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Operation> Operation { get; set; }
}
PRICE: defines the price for each operation and the currency type. (i.e.: A property can have the rent option - Operation - for X amount in USD currency, but another price registered for the same Operation in case of use another currency type )
public partial class Price
{
public long Id { get; set; }
public float? Amount { get; set; }
public string CurrencyCode { get; set; }
public long? OperationId { get; set; }
public virtual Operation Operation { get; set; }
}
Said that, I want to get all the records (actually are about 40K-50K), but only for a few properties. As I mentioned before, the Multimedia table can have a lot of records for each Property, but I only need the first one with the smaller Order value and sorted by DatePublished. After that, I need to convert the result into MapMarker object, which is as follows:
public class MapMarker : EstateBase
{
public long Price { get; set; }
public int Category { get; set; }
public List<Tuple<string, string, string>> Prices { get; set; }
}
In order to achieve this, I made the following:
public async Task<IEnumerable<MapMarker>> GetGeolocatedPropertiesAsync(int quantity)
{
var properties = await GetAllProperties().AsNoTracking()
.Include(g => g.GeoLocation)
.Include(m => m.Multimedia)
.Include(p => p.Operation).ThenInclude(o => o.Price)
.Include(p => p.Operation).ThenInclude(o => o.OperationType)
.Where(p => p.GeoLocation != null
&& !string.IsNullOrEmpty(p.GeoLocation.Address)
&& p.GeoLocation.Longitude != null
&& p.GeoLocation.Latitude != null
&& p.StatusCode == (byte)StatusCode.Online
&& p.Operation.Count > 0)
.OrderByDescending(p => p.ModificationDate)
.Take(quantity)
.Select(p => new {
p.Id,
p.Url,
p.GeneratedTitle,
p.GeoLocation.Address,
p.GeoLocation.Latitude,
p.GeoLocation.Longitude,
p.Domain,
p.Operation,
p.Multimedia.OrderBy(m => m.Order).FirstOrDefault().Resize360x266
})
.ToListAsync();
var mapMarkers = new List<MapMarker>();
try
{
foreach (var property in properties)
{
var mapMarker = new MapMarker();
mapMarker.Id = property.Id.ToString();
mapMarker.Url = property.Url;
mapMarker.Title = property.GeneratedTitle ?? string.Empty;
mapMarker.Address = property.Address ?? string.Empty;
mapMarker.Latitude = property.Latitude.ToString() ?? string.Empty;
mapMarker.Longitude = property.Longitude.ToString() ?? string.Empty;
mapMarker.Domain = ((Domain)Enum.ToObject(typeof(Domain), property.Domain)).ToString();
mapMarker.Image = property.Resize360x266 ?? string.Empty;
mapMarker.Prices = new List<Tuple<string, string, string>>();
foreach (var operation in property.Operation)
{
foreach (var price in operation.Price)
{
var singlePrice = new Tuple<string, string, string>(operation.OperationType.Name, price.CurrencyCode, price.Amount.ToString());
mapMarker.Prices.Add(singlePrice);
}
}
mapMarkers.Add(mapMarker);
}
}
catch (Exception ex)
{
throw;
}
return mapMarkers;
}
but the results take more than 14 minutes and this method could be called multiple times in a minute. I want to optimize it to return the results in the less time possible. I alreay tried removing ToListAsync(), but in the foreach loop it takes a lot of time too, and that makes all the sense.
So, what do you think I can do here?
Thanks in advance.
UPDATE:
Here is GetAllProperties() method, I forgot to include this one.
private IQueryable<Property> GetAllProperties()
{
return _dbContext.Property.AsQueryable();
}
And the SQL query that Entity Framework is making against SQL Server:
SELECT [p].[Id], [p].[Url], [p].[GeneratedTitle], [g].[Address], [g].[Latitude], [g].[Longitude], [p].[Domain], (
SELECT TOP(1) [m].[Resize360x266]
FROM [Multimedia] AS [m]
WHERE [p].[Id] = [m].[PropertyId]
ORDER BY [m].[Order]), [t].[Id], [t].[CreationDate], [t].[ModificationDate], [t].[OperationTypeId], [t].[PropertyId], [t].[Id0], [t].[CreationDate0], [t].[ModificationDate0], [t].[Name], [t].[Id1], [t].[Amount], [t].[CreationDate1], [t].[CurrencyCode], [t].[ModificationDate1], [t].[OperationId]
FROM [Property] AS [p]
LEFT JOIN [GeoLocation] AS [g] ON [p].[Id] = [g].[PropertyId]
LEFT JOIN (
SELECT [o].[Id], [o].[CreationDate], [o].[ModificationDate], [o].[OperationTypeId], [o].[PropertyId], [o0].[Id] AS [Id0], [o0].[CreationDate] AS [CreationDate0], [o0].[ModificationDate] AS [ModificationDate0], [o0].[Name], [p0].[Id] AS [Id1], [p0].[Amount], [p0].[CreationDate] AS [CreationDate1], [p0].[CurrencyCode], [p0].[ModificationDate] AS [ModificationDate1], [p0].[OperationId]
FROM [Operation] AS [o]
LEFT JOIN [OperationType] AS [o0] ON [o].[OperationTypeId] = [o0].[Id]
LEFT JOIN [Price] AS [p0] ON [o].[Id] = [p0].[OperationId]
) AS [t] ON [p].[Id] = [t].[PropertyId]
WHERE (((([g].[Id] IS NOT NULL AND ([g].[Address] IS NOT NULL AND (([g].[Address] <> N'') OR [g].[Address] IS NULL))) AND [g].[Longitude] IS NOT NULL) AND [g].[Latitude] IS NOT NULL) AND ([p].[StatusCode] = CAST(1 AS tinyint))) AND ((
SELECT COUNT(*)
FROM [Operation] AS [o1]
WHERE [p].[Id] = [o1].[PropertyId]) > 0)
ORDER BY [p].[ModificationDate] DESC, [p].[Id], [t].[Id], [t].[Id1]
UPDATE 2: As #Igor mentioned, this is the link of the Execution Plan Result:
https://www.brentozar.com/pastetheplan/?id=BJNz9KdQI
Ok, a few things that should help. #1. .Include() and .Select() should in general be treated mutually exclusive.
You are selecting:
p.Id,
p.Url,
p.GeneratedTitle,
p.GeoLocation.Address,
p.GeoLocation.Latitude,
p.GeoLocation.Longitude,
p.Domain,
p.Operation,
p.Multimedia.OrderBy(m => m.Order).FirstOrDefault().Resize360x266
but then in your foreach loop accessing Price and OperationType entities off it.
Edit Updated the example for the collection of operation. (Whups)
Instead I would recommend:
p.Id,
p.Url,
p.GeneratedTitle,
p.GeoLocation.Address,
p.GeoLocation.Latitude,
p.GeoLocation.Longitude,
p.Domain,
Operations = p.Operation.Select( o => new
{
OperationTypeName = o.OperationType.Name,
o.Price.Amount,
o.Price.CurrencyCode
}).ToList(),
p.Multimedia.OrderBy(m => m.Order).FirstOrDefault().Resize360x266
Then adjust your foreach logic to use the returned properties rather than a returned entity and related entity values.
Loading 40-50k records with something like that image field (MultiMedia) is potentially always going to be problematic. Why do you need to load all 50k in one go?
This looks like something that would put markers on a map. Solutions like this should consider applying a radius filter at the very least to get markers within a reasonable radius of a given center point on a map, or if loading a larger area (zoomed out map) calculating regions and filtering data by region or getting a count falling in that region and loading/rendering the locations in batches of 100 or so rather than potentially waiting for all locations to load. Something to consider.

Realm primary key not getting stored

Data Model:
public class Product : RealmObject
{
[PrimaryKey,JsonProperty(PropertyName = "productId")]
public int ProductId { get; set; }
[JsonProperty(PropertyName = "parentId")]
public int ParentId { get; set; }
[JsonProperty(PropertyName = "productType")]
public string ProductType { get; set; }
}
Method used to add product to db:
public void AddSampleProduct(Product product)
{
var _realm = Realm.GetInstance();
using (var transaction = _realm.BeginWrite())
{
var entry = _realm.Add(product);
transaction.Commit();
}
}
Method used to retrieve product:
public Product GetProductById(int id)
{
Product product = null;
var _realm = Realm.GetInstance();
product = _realm.Find<Product>(id);
var p = _realm.Find<Product>(id);
return product;
}
Method to fetch list of products:
public List<Product> GetProductList()
{
List<Product> productList = new List<Product>();
var _realm = Realm.GetInstance();
productList = _realm.All<Product>().ToList();
return productList;
}
Whenever I try to fetch a product using an id it returns null, at the same time if i try to fetch the list am getting all the products but with the primary key property having the value 0 for all the products. Probably the primary key is not getting stored and hence am not able to fetch individual product using id.
Also, in the model class I had tried defining the primary key and Json Property in separate lines like mentioned below.
public class Product : RealmObject
{
[PrimaryKey]
[JsonProperty(PropertyName = "productId")]
public int ProductId { get; set; }
[JsonProperty(PropertyName = "parentId")]
public int ParentId { get; set; }
[JsonProperty(PropertyName = "productType")]
public string ProductType { get; set; }
}

How can I get an object with all its navigation properties filled, in a database with TPH inheritance mapping using EF Core?

I have the following classes
public class Device
{
public int Id { get; set; }
public string MacAddress { get; set; }
public List<Input> Inputs { get; set; }
}
public abstract class Input
{
public int Id { get; set; }
public bool Active { get; set; }
}
public class InputCounter : Input
{
public bool Incremental { get; set; }
}
public class InputState : Input
{
public List<State> PossibleStates { get; set; }
}
public class State
{
public int Id { get; set; }
public string Description { get; set; }
}
and need to get a Device (with all its InputCounters and InputStates with its respectives States) by the MacAddress.
I'm querying the database this way
return _context.Devices.Select(device =>
new Device()
{
Id = device.Id,
MacAddress = _myMacAddress,
Inputs = device.Inputs.Where(input => input is InputCounter).Select(input =>
new InputCounter()
{
Id = input.Id,
Active = input.Active,
Incremental = (input as InputCounter).Incremental
} as Input
)
.Union(
device.Inputs.Where(input => input is InputState).Select(input =>
new InputState()
{
Id = input.Id,
Active = input.Active,
PossibleStates = (input as InputState).PossibleStates
}
)
).ToList<Input>()
}
).FirstOrDefault();
but it causes an ArgumentNullException.
What is the right way to do this query?
Obs: If I comment the line PossibleStates = (input as InputState).PossibleStates, the error doesn't happen, so I think the problem may be related with typecast. However, the line Incremental = (input as InputCounter).Incremental don't cause any problem.
In Database, I have:
Device table with Id and MacAddress fields;
Input table, with Id, DeviceId, Active, Incremental and Discriminator fields;
State table, with Id, InputStateId and Description fields.

how to combine the result from differentviews to IQueryable<T>

i have a list of PlanItems bind to telerik RadGrid and have two views retrieves the result.Each view get different data so how can i get that data into IQueryable
public class PlanItems
{
public int Id{get; set;}
public string Name { get; set; }
public string HV { get; set; }
public string StNumber { get; set; }
public string LDNumber { get; set; }
public string MSId { get; set; }
public string CreatedBy { get; set; }
public string Type { get; set; }
}
I have 2 different views vw_Boys ,vw_Girls and Student Entity
first i got boys_Id and Girls_Id from student Entity
public IQuerable<PlanItems> GetAllStudents()
{
var Id = from v in context.Student
.Include("SBoy")
.Include("SGirl")
where v.CreatedBy_Id == user.Id
select v;
var temp = unp.Select(a=>a.SBoy.boys_Id).Distinct();
var temp1 = unp.Select(a => a.SGirl.girls_Id).Distinct();
var vwboys = from nv in context.vw_boys
where(temp.Contains(nv.SId))
select nv;
var vwgirls= from nv in context.vw_girls
where (temp1.Contains(nv.GId))
select nv;
var Boysresult = from n in vwboys
select new PlanItems
{
Id = n.SId,
Name = n.Name,
HV = n.HV,
StNumber = n.SNumber,
LDNumber = n.LineNumber,
MSId = n.MasterId,
CreatedBy = n.USerName,
Type = n.SubjectType
};
var GirlsResult = from n in vwgirls
select new UnplannedItems
{
Id = n.GiId,
Name = n.Name,
HV = n.GV,
StNumber = n.SujNumber,
LDNumber = n.Lid,
MSId = n.MasterId,
CreatedBy = n.USerName,
Type = n.SubjectType
};
}
my telerikGrid sample
<telerik:GridViewDataColumn Header="StudentID" IsReadOnly="True" DataMemberBinding="{Binding ID, Mdde=OneWay}" />
how can i return the result from above method..how can i combine the result to one.
I would do it something like this.
Add a new property to you class like this. Because you might have to seperate the boys from the girls in a other case:
public class PlanItems
{
public int Id{get; set;}
public string Name { get; set; }
public string HV { get; set; }
public string StNumber { get; set; }
public string LDNumber { get; set; }
public string MSId { get; set; }
public string CreatedBy { get; set; }
public string Type { get; set; }
//new property
public bool IsUnplanned { get; set; }
}
The use a concat between them like this:
var result= (
from n in vwboys
select new PlanItems
{
Id = n.SId,
Name = n.Name,
HV = n.HV,
StNumber = n.SNumber,
LDNumber = n.LineNumber,
MSId = n.MasterId,
CreatedBy = n.USerName,
Type = n.SubjectType,
IsUnplanned=false
}
).Concat
(
from n in vwgirls
select new PlanItems
{
Id = n.GiId,
Name = n.Name,
HV = n.GV,
StNumber = n.SujNumber,
LDNumber = n.Lid,
MSId = n.MasterId,
CreatedBy = n.USerName,
Type = n.SubjectType,
IsUnplanned=true
}
);
Hope this helps
You can union 2 different IQueryable using union extension method :
here's an example
I am not an expert in wpf, but looking at the solution I think you can use a parent class for both Boys and Girls and then add to a list of that class.
lets say both Boy and Girl classes are inherited from Person class, then create
List<Person> personList = new List<Person>()
and add Boys and Girls into this list.
I am not sure whether this is the solution you need

Resources