I am working through this Xaml Brewer article and altering it slightly to use my models. It uses a generic MasterDetailViewModel base class of type T.
The base class is declared thus
public abstract partial class MasterDetailViewModel<T> : ObservableObject
{
private readonly ObservableCollection<T> items = new();
etc...
My derived class declares as .
public partial class HomePageViewModel : MasterDetailViewModel<Tenant>
{
etc..
Class Tenant is
[Table("tenants")]
public partial class Tenant
{
//[Column("email")]
public string Email { get; set; }
//[Column("first_name")]
public string FirstName { get; set; }
[Key]
public int Id { get; set; }
etc..
My derived class contains a RelayCommand and a method
[RelayCommand]
private void Delete(int param) //param is Id of selected list item
{
DeleteCommand_Executed(param);
}
private void DeleteCommand_Executed(int parm)
{
if (parm > 0)
{
var toBeDeleted = Items.First(c => c.Id == parm); //get the record with this Id
DeleteItem(toBeDeleted); //delete from the database
}
}
I want to move the RelayCommand and DeleteCommand_Executed method up into the base class. If I just move the relay command into the base class and add this protected abstract void DeleteCommand_Executed(int parm);
then with this in the derived class protected override void DeleteCommand_Executed(int parm) etc.
it all works fine but if I move DeleteCommand_Executed into the base class I get this error
Error (active) CS1061 'T' does not contain a definition for 'Id' and no accessible extension method 'Id' accepting a first argument of type 'T' could be found (are you missing a using directive or an assembly reference?)
I have tried adding a type identifier var toBeDeleted = Items.First<T>(c => c.Id == parm);
I have looked at a few similar questions on SO and a couple of googled items and I think what I'm being told is that the T is not known until the expression has run so it cant know what properties T has? So is it possible to achieve my aim of putting everything into the base class?
Thanks in advance
First, define an interface like below:
public interface IHasId
{
int Id { get; set; }
}
Then, redefine MasterDetailViewModel
and Tenant
classes like this:
public abstract partial class MasterDetailViewModel<T> : ObservableObject where T: IHasId
public partial class Tenant : IHasId
Now, moving the DeleteCommand_Executed
method to the MasterDetailViewModel
class should work fine.