MVC design pattern for multiplatform lib - c#

I currently have a design problem currently on a personal project, I'm developing both an Android app (using xamarin) and a C# wpf windows application.
The application on desktop help the user to design some exercices that the student on the android app can practice. But currently, I want to have a good structure for the code, by principally having a common lib to both apps. The problem is, following the MVC design pattern, everything in my model should be independent from the view. Or, on Android I need to keep track when an exercise is running, and what button the student pressed. Or this kind of information is not saved after the exercise is done, and from the windows app point of view it's useless information. So in this case should I write a kind of wrapper around my model for the android app so I can save this data ? It seems that doing this way is going against the MVC pattern, but I can't find a solution to this. To better illustrate my problem here is my model :
public class File
{
public string Name { get; set; } = "file";
public List<Module> Modules { get; set; } = new List<Module>();
}
public class Module
{
public string Title { get; set; } = string.Empty;
public string Color { get; set; } = "0xFF0000";
public List<Exercice> Exercices { get; set; } = new List<Exercice>();
}
public class Exercice
{
public string Name { get; set; } = string.Empty;
public List<string> Sounds { get; set; } = new List<string>();
public List<Unit> Units { get; set; } = new List<Unit>();
public bool Randomize { get; set; } = false;
}
public class Unit
{
public string Text { get; set; } = string.Empty;
public List<string> Sounds { get; set; } = new List<string>();
public EType Type { get; set; }
public bool Solution { get; set; } = true;
public List<UnitChild> Units { get; set; } = new List<UnitChild>();
}
public class UnitChild
{
public string Text { get; set; } = string.Empty;
public List<string> Sounds { get; set; } = new List<string>();
public EType Type { get; set; }
public bool Solution { get; set; } = true;
}
public enum EType
{
Touch,
Display,
Voice
}
Everything is loaded and parsed from a YAML file, because I need this to be really structured.
In each of this class, I don't want to keep (in Unit and UnitChild classes) which one has been pressed, because it's superfluous and maybe need to be saved in the controller (which I currently didn't wrote, since I want to figure this out before the actual coding). Basically, all the fields are the core of the exercices, and is the only data needed for the Windows app.
Thanks for your help !
I hope this does not look messy

I figured this out by myself,
While reading documents on MVC design pattern, and more specific articles on C# WPF programming.
If you're in my situation, what you need to do is to keep your model clean and keeping only shared variables in both apps, and app specific variables in the controller, since he is the one making the link between the View and the Model.

Related

Create entity class from existing class using T4 templating

I need to easily create/automate some boilerplate code from a simple class in C#/.NET. I have found the T4 templating engine, but I am hoping someone can perhaps give some guidence on how best to implement and if I am on the right track.
I have classes that all look very similar to this:
using System;
using System.Collections.Generic;
namespace BarryAPI.Api
{
public partial class Client
{
public int Id { get; set; }
public int OrganId { get; set; }
public string Title { get; set; } = null!;
public string FirstName { get; set; } = null!;
public string LastName { get; set; } = null!;
public DateTime DateOfBirth { get; set; }
public string Gender { get; set; } = null!;
public int AddressId { get; set; }
public string? Phone { get; set; }
public string? Mobile { get; set; }
}
}
And I am trying to (mostly) automate the creation of a matched class that looks like this:
using System.ComponentModel.DataAnnotations.Schema;
using Barry.Domain.Entities.Client.Email;
using Barry.Domain.Entities.Organisation;
using Barry.Infrastructure;
namespace Barry.Domain.Entities.Client;
[Table("Client")]
public class ClientEntity : Entity, IMapFrom<ClientDto>
{
public const int TitleMaxLength = 50;
public const int FirstNameMaxLength = 100;
public const int LastNameMaxLength = 100;
public const int GenderMaxLength = 20;
public const int PhoneMaxLength = 20;
public const int MobileMaxLength = 60;
#nullable disable
public ClientEntity()
{
}
#nullable restore
public string Title { get; set; } = null!;
public string FirstName { get; set; } = null!;
public string LastName { get; set; } = null!;
public DateTime DateOfBirth { get; set; }
public string Gender { get; set; } = null!;
public int AddressId { get; set; }
public string? Phone { get; set; }
public string? Mobile { get; set; }
}
I understand I cannot make all the logic decisions in the template (Like MaxLength etc), but I am hoping to automate the bulk of it as there as many classes that need to be converted into entity models.
I have looked into T4, but I am struggling to know if this is the correct choice. Can anyone please shed a little light on this problem and if I am headed down the right path trying to solve it with T4?
I've been tasked with writing something up to semi-automate this process (mostly just to automate the typing/copy/paste by hand) and I am not sure if a simple console app to read the file and output what's required would be more efficient? Would it?
If you think T4 is the go, pointing towards a similar case tutorial/docs that you know of would be a huge help.
Thank you.
T4 templates and execution subsystem not designed to EDIT any of existing files - T4 used to generate whole file and replace existing one.
You can put any logic you want in T4-template or in side DLL's used by the template. Any, including any kind of parsing existed C#/VB/F#&etc files. Just pay attention to complexity of T4-template - it difficult to support when pieces of text mixed with complex code.

Public C# Properties are invisible on Xamarin Forms Android

My Xamarin Forms app is acting strangely when running on Android. When I run on UWP everything appears to work fine, but when I launch the same app on Android, the public properties of the model I'm binding seem to disappear, as if they don't exist.
The model is defined as an interface as shown here:
public interface IRegionModel
{
string Id { get; set; }
string Name { get; set; }
string ShortName { get; set; }
string UrlName { get; set; }
string Description { get; set; }
string CityId { get; set; }
}
the implementation is pretty much identical:
public class RegionModel : IRegionModel
{
public string Id { get; set; }
public string Name { get; set; }
public string ShortName { get; set; }
public string UrlName { get; set; }
public string Description { get; set; }
public string CityId { get; set; }
}
and I'm populating my ViewModel with an observable collection of the RegionModel type:
public class RegionListViewModel : ViewModelBase
{
public ObservableCollection<IRegionModel> Regions { get; set; } = new ObservableCollection<IRegionModel>();
protected string CityId { get; set; }
public void Init(string cityId)
{
CityId = cityId;
}
public async override void Start()
{
base.Start();
LoadDesignData();
IsLoading = false;
}
protected override void LoadDesignData()
{
base.LoadDesignData();
for (var i = 1; i < 5; i++)
{
var model = new RegionModel()
{
Id = i.ToString(),
Description = "Region description " + i.ToString(),
ShortName = "Downtown",
Name = "Downtown",
UrlName = "Downtown",
CityId = "mcallen"
};
Regions.Add(model);
}
}
}
as you can see, I have access to each of the properties of the model, and populate them with my properties.
however when I run the app on android, these properties are immediately invisible:
I don't get any exceptions or errors, but the properties are simply not there.
I thought perhaps it was due to stale binaries (as suggested here: C# some public properties are not accessible, actually completely missing)
However, I did a full clean and manual clean, clearing out all the bin/obj folders manually on every single project and rebuilt it. In addition I made some code changes and XAML changes and those are showing up, so the project definitely appears to be updating...
what else could possibly be wrong here? How can properties just disappear?
If you have linked your assemblies the analyzer may have failed to determine those properties are really used and it has stripped them.
Set the linkage options to "SDK Only" and it should work.

Creating class members during run time - C#

I have a simple class defined like this:
public class StickColumns
{
public string wellname { get; set; }
public double WellLength { get; set; }
}
In the code, I get some data as list<double> perfdepth; assume this is perfdepth1,perfdepth2,perfdepth3. Of course, this list is dynamic hence, I wouldnt know beforehand to change my class definition to:
public class StickColumns
{
public string wellname { get; set; }
public double WellLength { get; set; }
public double perfdepth1 { get; set; }
public double perfdepth2 { get; set; }
public double perfdepth3 { get; set; }
}
Can these new members be created during run time?
The reason why I think I would need this is because of data binding in WPF. Eventually I need to display "point series"; Perfdepth1 as one series, perfdepth2 as another series and so on, i.e, dynamic number of Perfdepths.
If there is a simpler way to do it, I am all ears!
You might just want to use the dynamic type with ExpandoObject..
dynamic stickColumns = new ExpandoObject();
stickColumns.wellName = "Something";
stickColumns.perfdepth1 = "Something Else";
It has its drawbacks as it does mean you end up with runtime errors etc... but it can be useful for this type of scenario.

Count depth of a hierarchy of classes

I've seen a lot of different examples of how to do this and am well aware that I could write out a loop that iterates my entire tree of classes to find the maximum depth, but I cannot help but think there has to be a simpler way.
Basically I have two classes that I developed to host all my applications settings, SettingGroup which is exactly what it sounds like, basically a folder, and Setting which is the setting itself and the configurations that allow the application to know what the setting is for and how to display it. The reason I dont just use a fixed class and write out field for my settings is that the application is plugin driven and I wish the settings to remain centralized is plugins are added or removed and not have to worry about decentralized data from the plugins.
When dynamically creating the settings page it is necessary to know the maximum depth of any particular SettingGroup so I know if the root should first organized by tabs, pages, sections etc...
Long story short, is there a reasonably lightweight way to determine the groups maximum depth?
public enum DescriptionVisibility { None, SubText, ToolTip };
public enum SettingType { Bool, Integer, Decimal, Text };
public enum SettingControl { Checkbox, Textbox, Slider, Radio, Dropdown, TextField, Color};
public class SettingGroup
{
public string name { get; set; }
public string description { get; set; }
public List<SettingGroup> groups { get; set; }
public List<Setting> settings { get; set; }
}
public class Setting
{
public string name { get; set; }
public string description { get; set; }
public DescriptionVisibility descriptionVisibility { get; set; }
public Dictionary<string, dynamic> configuration { get; set; }
public dynamic settingValue { get; set; }
public SettingType settingType { get; set; }
public SettingControl settingControl { get; set; }
}
Edit: this is untested, but this is what I am currently considering using;
private static int getDepth(this SettingGroup group, int depth = 0)
{
if (group.groups == null)
return depth;
if (group.groups.Count == 0)
return depth;
int returnDepth = depth;
foreach (SettingGroup subGroup in group.groups)
{
int subGroupDepth = subGroup.getDepth(depth + 1);
if (subGroupDepth > returnDepth)
returnDepth = subGroupDepth;
}
return returnDepth;
}
Its pretty basic so it couldn't be TOO slow, but still seems bulky, is there not a LINQ way to do this perhaps?

WPF observablecollection. Modify from child window

This is my collection:
public ObservableCollection<CheckOutData> _CheckOutCollection = new ObservableCollection<CheckOutData>();
public ObservableCollection<CheckOutData> CheckOutCollection
{
get { return _CheckOutCollection; }
}
public class CheckOutData
{
public int ID { get; set; }
public string RoomType { get; set; }
public string RoomNumber { get; set; }
public decimal RoomPrice { get; set; }
public string RoomPriceWithCurrency { get; set; }
public decimal Discount { get; set; }
public decimal DiscountedPrice { get; set; }
public string DiscountedPriceWithCurrency { get; set; }
public string CheckIn { get; set; }
public string CheckOut { get; set; }
public int TotalDay { get; set; }
public string CheckOutHour { get; set; }
}
I have another window where i want to do following: Add CheckOutData public string serviceName{get;set}
how can this done? i dont even see checkoutdata in my child window.
So my main task is add new collection in checkoutdata and then rebind datagrid. Can anyone help me?
private CheckOut m_parent;
public AddActionService(CheckOut parent)
{
InitializeComponent();
m_parent = parent;
}
You might want to consider some sort of event aggregator. This way any form's code (or ViewModel/Presenter, if you're using MVVM/MVP) can send messages that are picked up by the aggregator and distributed to any other forms/ViewModels/Presenters that have subscribed to that event. This approach means your forms are no longer tightly coupled together. They literally have no reference to each other at all. They communicate through the event aggregator and they don't even know if any objects are listening for those events.
You could also consider taking it one step further and going for a "Domain Events" style, that allows you to react to these events not just in UIs, but also in domain objects elsewhere in your system, including sending messages via external services to call web services, update databases, put messages in queues etc.

Categories