How does ReactiveTableViewSource<TSource> work? - mvvm

In our app we use ReactiveUI to follow the MVVM pattern. In one view we want to show a UITableView. Data are usually passed to a UITableView.Source but with ReactiveUI we use ReactiveTableViewSource<TSource>.
What I don't understand is how I can bind my data that I got in my view model in a ReactiveList to the ReactiveTableViewSource.
What we now have is that we create a table inside a UIView like this:
Table = new UITableView(UIScreen.MainScreen.Bounds);
Table.Source = new TableSource(Table, MyReactiveList, (NSString) CellIdentifier, _cellHeight, cell => Debug.WriteLine(cell));
Btw: What is the cell action used for?
Furthermore we have a Table source class that looks like this:
internal sealed class TableSource : ReactiveTableViewSource<MyListObject>
{
public TableSource(UITableView tableView, IReactiveNotifyCollectionChanged<MyListObject> collection, NSString cellKey, float sizeHint, Action<UITableViewCell> initializeCellAction = null) : base(tableView, collection, cellKey, sizeHint, initializeCellAction)
In my view model I have a service that is updating my ReactiveList. It looks like this:
public sealed class MyService : ReactiveObject, IMyService
{
public IReactiveList<MyListObject> MyReactiveList { get; }
public async Task UpdateMyReactiveListAsync() {//...}
Where do I bind the table source to the ReactiveList? Where do I subscribe for events? Is there any documentation or example code I might have missed?

Working with ReactiveTableViewSource is quite easy:
Just connect the List with your UITableView
var tableView = new UITableView ();
// Bind the List agains the table view
// SampleObject is our model and SampleCell the cell
ViewModel.WhenAnyValue (vm => vm.Items).BindTo<SampleObject, SampleCell> (tableView, 46, cell => cell.Initialize());
Then create a custom cell where you bind the model data against the cell.
public class SampleCell : ReactiveTableViewCell, IViewFor<SampleObject>
{
public SampleCell () : base() { }
public SampleCell (IntPtr handle) : base(handle) { }
private SampleObject _viewModel;
public SampleObject ViewModel
{
get { return _viewModel; }
set { this.RaiseAndSetIfChanged (ref _viewModel, value); }
}
object IViewFor.ViewModel
{
get { return ViewModel; }
set { ViewModel = value as SampleObject; }
}
public void Initialize()
{
this.WhenAnyValue (v => v.ViewModel.Name).BindTo (
this,
v => v.TextLabel.Text);
}
}
A compelling example you can find here: https://github.com/reicheltp/ReactiveTableViewSource-Sample
Update 2016/03/09: Better do binding in a separated Initialize method to prevent multiple calls.
If you have more questions you can ask me on twitter: #reicheltp

May be you miss this https://github.com/reactiveui/ReactiveUI/blob/275eca3dc2e5fc93bddb137e60be32885f788688/docs/basics/rx-cocoa-delegates.md
To subscribe the event you can assign a UITableViewDelegateRx
var tvd = new UITableViewDelegateRx ();
Table.Delegate = tvd;
tvd.RowSelectedObs.Subscribe (c => { });

Just to make a small update using ReactiveUI version 9.16.6:
Example that lists some cities with their according postal codes.
=> My ViewController inherites from ReactiveViewController
=> My CityViewModel inherites from ReactiveObject
=> My CityItemViewModel inherites from ReactiveObject
=> My CityTableViewCell inherites from ReactiveTableViewCell
public class CityViewModel : ReactiveObject
{
private ICityService CityService { get; }
private SourceCache<CityItemViewModel, int> _citiesCache;
private IObservable<IChangeSet<CityItemViewModel, int>> _citiesOperations => _citiesCache.Connect();
public readonly ReadOnlyObservableCollection<CityItemViewModel> Cities;
public CityViewModel(ICityService cityService)
{
CityService = cityService;
}
#region CityViewModelCommand
public ReactiveCommand<CityItemViewModel, Unit> CityClickCommand { get; }
#endregion
private async Task<IEnumerable<CityItemViewModel>> SearchCitiesAsync(string searchText, CancellationToken token)
{
IEnumerable<CityItemViewModel> items;
if (string.IsNullOrEmpty(searchText))
items = await CityService.ToListWithCountryCodeAsync(cancellationToken: token);
else
items = await CityService.ToListBySearchWithCountryCodeAsync(searchText, cancellationToken: token);
_citiesCache.Edit(innerList =>
{
innerList.Clear();
innerList.AddOrUpdate(items);
});
return items;
}
}
public class CityItemViewModel : ReactiveObject
{
public int Id { get; set; }
public string Name { get; set; }
public string PostalCode { get; set; }
public override string ToString()
=> $"[CityItemViewModel: Id={Id}, Name={Name}, PostalCode={PostalCode}]";
public CityItemViewModel() : base()
{
}
}
In my ViewController's ViewDidLoad method:
this.WhenActivated((cleanup) =>
{
this.Bind(ViewModel,
x => x.SearchText,
x => x.searchBar.Text)
.DisposeWith(cleanup);
this.WhenAnyValue(v => v.ViewModel.Cities)
.BindTo<CityItemViewModel, CityTableViewCell>(tableView, CityTableViewCell.Key, 50, cell => cell.Initialize(),
source => source.ElementSelected.InvokeCommand(ViewModel.CityClickCommand))
.DisposeWith(cleanup);
});
In my Initialize method of my UITableViewCell:
public void Initialize()
{
this.WhenAnyValue(v => v.ViewModel.Name)
.Subscribe(name => cityLabel.Text = name);
this.WhenAnyValue(v => v.ViewModel.PostalCode)
.Subscribe(x => postalCodeLabel.Text = x);
}
Hope that can help someone ;)

Related

How to query the DbSets of all types that implement an interface?

Many of my data models use this interface:
public interface IHasPrimaryImageProperty
{
PrimaryImageDataModel PrimaryImage { get; set; }
int? PrimaryImageId { get; set; }
}
Where PrimaryImageDataModel is:
public class PrimaryImageDataModel
{
public int Id { get; set; }
public string ImageFile { get; set; }
public int TotalItemsUsingImage { get; set; }
}
I want populate PrimaryImageDataModel.TotalItemsUsingImage, by performing counts on all data models that implement IHasPrimaryImageProperty.
So far I have managed to get a list of types that implement the IHasPrimaryImageProperty.
But I haven't been able to get the total for each Type.
Please see the example below for a demonstration of what I would like to acheive.
public static PrimaryImageDataModel GetImageUsageTotals(PrimaryImageDataModel image)
{
var typesUsingImage = GetTypesWithPrimaryImageProperty();
int totalUsingImage = 0;
foreach (Type typeUsingImage in typesUsingImage)
{
// I WOULD LIKE TO DO SOMETHING LIKE THIS
totalForType = db.Set<typeUsingImage>()
.Where(x => x.PrimaryImageId == image.Id)
.Count()
totalUsingImage += totalForType;
}
image.TotalItemsUsingImage = totalUsingImage;
return image;
}
public static IEnumerable<Type> GetTypesWithPrimaryImageProperty()
{
var currentAssembly = Assembly.GetExecutingAssembly();
foreach (Type type in currentAssembly.GetTypes())
{
if (type.GetInterfaces().Contains(typeof(IHasPrimaryImageProperty)))
{
yield return type;
}
}
}
The simplest I see (works in both EF6 and EF Core) is to create a generic method and call it via reflection.
For instance:
static int CountUsage<T>(DbContext db, PrimaryImageDataModel image)
where T : class, IHasPrimaryImageProperty
{
return db.Set<T>()
.Where(x => x.PrimaryImageId == image.Id)
.Count();
}
static readonly MethodInfo CountUsageMethodInfo = typeof(YourClass)
.GetMethod("CountUsage", BindingFlags.NonPublic | BindingFlags.Static);
public static PrimaryImageDataModel GetImageUsageTotals(PrimaryImageDataModel image)
{
var args = new object[] { db, image };
image.TotalItemsUsingImage = GetTypesWithPrimaryImageProperty()
.Sum(type => (int)CountUsageMethodInfo.MakeGenericMethod(type).Invoke(null, args));
return image;
}
IQueryable is covariant. See Variance in Generic Interfaces (C#) This allows an IQueryable<SomeEntity> to be cast to IQueryable<InterfaceType>, for interfaces implemented by that Entity type.
So if you put this method on your EF6 DbContext type:
public IQueryable<T> GetQuery<T>(Type EntityType)
{
return (IQueryable<T>)this.Set(EntityType);
}
Or like this for EF Core:
public IQueryable<T> GetQuery<T>(Type EntityType)
{
var pq = from p in this.GetType().GetProperties()
where p.PropertyType.IsGenericType
&& p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)
&& p.PropertyType.GenericTypeArguments[0] == EntityType
select p;
var prop = pq.Single();
return (IQueryable<T>)prop.GetValue(this);
}
Then you can write
foreach (Type typeUsingImage in typesUsingImage)
{
// I WOULD LIKE TO DO SOMETHING LIKE THIS
totalForType = db.GetQuery<IHasPrimaryImageProperty>(typeUsingImage)
.Where(x => x.PrimaryImageId == image.Id)
.Count()
totalUsingImage += totalForType;
}

Using sets of Entity Framework entities at runtime

I have an EF6 setup against a sql server db with about 60 tables in it.
I have entities for each table. What i'm trying to do is run the same method against a set of these entities that will be known at runtime.
The method is a qa/qc routine that does some data check on particular fields that are assured to be in each table.
I guess what i want to do is make the entity a parameter to the method so i can call it consecutive times.
I would also want to make a set of entities to pass as the parameter.
something like this:
List<string> entList = new List<string>(){"Table1","Table2","Table3"};
foreach (entName in entList)
{
//create an entity with the string name
//call myQAQCMethod with the entity
}
MyQAQCMethod (entity SomeEntity)
{
//run against this entity
doQAQC(SomeEntity);
}
Can this be done? Is it a job for reflection?
EDIT
using (var context = new Context())
{
var results = context.EntityAs.Where(a => a.Prop1 == e.Prop1)
.Where(a => a.Prop2 == e.Prop2)
.Select(a => new
{
APropertyICareAbout = a.Prop1,
AnotherPropertyICareAbout = a.Prop2
}).ToArray();
}
is precisely want i want to do. The thing is I want to avoid typing this loop 60 times. I think i'm looking for a way to "feed" a set of entities to this single method.
Also, thank you very much for helping me. I'm learning a lot.
You need to abstract an interface (entity framework won't even notice):
interface IQaQcable
{
int CommonInt { get; set; }
string CommonString { get; set; }
}
public class EntityA : IQaQcable
{
public int Id { get; set; }
public int CommonInt { get; set; }
public string CommonString { get; set; }
// other properties and relations
}
public class EntityB : IQaQcable
{
public int Id { get; set; }
public int CommonInt { get; set; }
public string CommonString { get; set; }
// other properties and relations
}
// in some unknown utility class
void MyQaQcMethod<T>(T entity) where T : IQaQcable
{
doSomethingWithIQaQcableProperties(entity.CommonInt, entity.CommonString);
}
// in some unknown test class
void Test()
{
var entities = new List<IQaQcable> { new EntityA(), new EntityB() };
foreach (var e in entities)
MyQaQcMethod(e);
}
Now, you could extract a base class from which each derives that actually implements the CommonInt and CommonString properties for each entity needing them, but that can get kind of tricky with Table-Per-Type/Table-Per-Hierarchy, so I'd start with this, and then consider introducing either an abstract or concrete base class as an improvement.
EDIT
Maybe your looking for something simpler than I first thought, based on your last comment.
Let's give ourselves what the DbContext for this might look like:
class Context : DbContext
{
public virtual DbSet<EntityA> EntityAs { get; set; }
public virtual DbSet<EntityB> EntityBs { get; set; }
}
So, it could just be that you wish to do this:
using (var context = new Context())
{
var results = context.EntityAs.Where(a => a.Prop1 == e.Prop1)
.Where(a => a.Prop2 == e.Prop2)
.Select(a => new
{
APropertyICareAbout = a.Prop1,
AnotherPropertyICareAbout = a.Prop2
}).ToArray();
}
Keeping in mind, if there is some set of properties in common across entity classes, you could still do something like the following:
IEnumerable<T> MyQaQcMethod(IQueryable<T> entities, T referenceEntity) where T : IQaQcAble
{
return entities.Where(e => SomePredicate(e, referenceEntity));
}
void Test()
{
using (var context = new Context())
{
// EntityA implements IQaQcAble
var resultsForA = MyQaQcMethod(context.EntityAs, defaultEntity).ToArray();
// so does EntityB, so can call with either
var resultsForB = MyQaQcMethod(context.EntityBs, defaultEntity).ToArray();
}
}
Keep in mind, to avoid modifying the generated entity classes, you could implement the interface members — and the interface — in a separate source file using partial classes. E.g.
// IQaQcAble.cs
internal interface IQaQcAble
{
int CommonInt { get; set; }
string CommonString { get; set; }
}
// a class whose existing property names match the interface
public partial class EntityA : IQaQcAble
{
int IQaQcAble.CommonInt
{
get { return CommonInt; }
set { CommonInt = value; }
}
string IQaQcAble.CommonString
{
get { return CommonString; }
set { CommonString = value; }
}
}
// a class whose property names differ
public partial class EntityB : IQaQcAble
{
int IQaQcAble.CommonInt
{
get { return SomeOtherInt; }
set { SomeOtherInt = value; }
}
string IQaQcAble.CommonString
{
get { return SomeOtherInt.ToString(); }
set { SomeOtherInt = Convert.ToInt32(value); }
}
}

How to get a property name of a given type strongly typed revisited?

How can I simplify the code below to avoid to pass the object for type inference on the generic method?
using System;
using System.Linq.Expressions;
namespace lambda
{
class Program
{
static void Main(string[] args)
{
var area = new Area { Name = "New Area" };
var propertyName = area.GetPropertyName(area, a => a.Name); // propertyName is COMPILE time checked
Console.WriteLine(propertyName);
}
}
public class Area
{
public int Id;
public string Name { get; set; }
}
public static class Extension
{
public static string GetPropertyName<T>(this Area entity, T e, Expression<Func<T, object>> path) // T e for type inference
{
var member = path.Body as MemberExpression;
if (member == null) throw new ArgumentException();
return member.Member.Name;
}
}
}
I mean instead of calling the extension method with area.GetPropertyName(area, a => a.Name)
just do a call like this area.GetPropertyName(a => a.Name), avoid to pass there area object just for type inference
I guess that I can’t do unless I refactor the signature of the method to GetPropertyName(this IEntity entity, Expression> path)
But in that case will be less obvius want I want at code writing time since I will need to specify the type on every call
I mean area.GetPropertyName( a => a.Name) seems to bel for me less clear writing code than writing area.GetPropertyName(area, a => a.Name)
The example code below works fine with asked requirements, no need to pass the object itself for type inference when calling the extension method
I used a base class and an interface that for my case works fine for all my domain class.
See code below
namespace UnitTestProject
{
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq.Expressions;
public interface IEntity<T>
{
}
public abstract class Entity<T> : IEntity<T> where T : class
{
}
public class Area : Entity<Area>
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Created { get; set; }
public bool Closed { get; set; }
public string Description { get; set; }
}
public static class EntityExtension
{
public static string GetPropertyName<T>(this IEntity<T> entity, Expression<Func<T, object>> expr) // T e for type inference
{
var unary = expr.Body as UnaryExpression;
var member = expr.Body as MemberExpression;
return member != null ? member.Member.Name : (unary != null ? ((MemberExpression)unary.Operand).Member.Name : String.Empty);
}
}
[TestClass]
public class UnitTest
{
[TestMethod]
public void GetPropertyName_Tests()
{
var area = new Area();
var x = area.GetPropertyName(a => a.Id);
var y = area.GetPropertyName(a => a.Name);
var v = area.GetPropertyName(a => a.Created);
var w = area.GetPropertyName(a => a.Closed);
var z = area.GetPropertyName(a => a.Description);
Assert.AreEqual(x, "Id");
Assert.AreEqual(y, "Name");
Assert.AreEqual(v, "Created");
Assert.AreEqual(w, "Closed");
Assert.AreEqual(z, "Description");
}
}
}

Entity Framework Fluent API ICollection.count (one to many)

I am new to EF and i have the following scenario:
I want to load the IHave apples without loading the whole Apples collection.
The model:
public class Category
{
public virtual ICollection<Classified> Apples { get; set; }
[NotMapped]
public bool IHaveApples {get { return Apples.count > 0; } }
}
And the FLUENT API Config:
public class CategoryConfiguration : EntityTypeConfiguration<Category>
{
public CategoryConfiguration()
{
HasMany(o => o.Apples ).WithRequired().HasForeignKey(o => o.CategoryId);
}
}
And in my controller i go with
//The controller returns IQueryable<Category>
var category = _contextProvider.Context.Categories;
Thanks in advance,
Stelios K.
As IHaveApples is a bool, you should simply use Apples.Any() instead of Count.
EDIT:
If you want this to be automatically set (i.e. the boolean is set without even accessing manually to your collection), what you could do is add an handler to the ObjectMaterialized event:
public class Category
{
...
public bool IHaveApples { get; set; }
}
((IObjectContextAdapter)yourDbContext).ObjectContext.ObjectMaterialized += (sender, e) =>
{
var entityAsCategory = e.Entity as Category;
if (entityAsCategory != null)
{
entityAsCategory.IHaveApples = yourDbContext
.Entry(entityAsCategory)
.Collection(z => z.Apples)
.Query()
.Any();
}
};

Why the ViewModel doesn't implement ICommand in MVVM

I'm trying to understand MVVM for WPF applications
In the example below, we use a delegate that inherits from ICommand, then in our ViewModel, we instantiate the delegate and provide the appropriate implementation
My Question is why can't we just make the ViewModel implement ICommand?
ViewModel :
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
InitializeViewModel();
}
protected void InitializeViewModel()
{
DelegateCommand MyCommand = new DelegateCommand<SomeClass>(
SomeCommand_Execute, SomeCommand_CanExecute);
}
void SomeCommand_Execute(SomeClass arg)
{
// Implementation
}
bool SomeCommand_CanExecute(SomeClass arg)
{
// Implementation
}
}
DelegateCommand :
public class DelegateCommand<T> : ICommand
{
public DelegateCommand(Action<T> execute) : this(execute, null) { }
public DelegateCommand(Action<T> execute, Predicate<T> canExecute) : this(execute, canExecute, "") { }
public DelegateCommand(Action<T> execute, Predicate<T> canExecute, string label)
{
_Execute = execute;
_CanExecute = canExecute;
}
.
.
.
}
The reason would be having a one to many relationship between your view and your number of commands.
You typically will have one ViewModel for every View. But you may want to have many Commands for a single view. If you were to use your ViewModel as a Command, you would have to have multiple instances of your ViewModel.
The typical implementation would be that your ViewModel would contain instances of all of the Commands your View needs.
Short answer: because your ViewModel isn't a command.
Moreover, your ViewModel can hold multiple commands.
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
InitializeViewModel();
OpenCommand = new DelegateCommand<SomeClass>(
param => { ... },
param => { return true; });
SaveCommand = new DelegateCommand<SomeClass>(
param => { ... },
param => { return true; });
SaveAsCommand = new DelegateCommand<SomeClass>(
param => { ... },
param => { return true; });
}
public ICommand OpenCommand { get; private set; }
public ICommand SaveCommand { get; private set; }
public ICommand SaveAsCommand { get; private set; }
}
Now you can binding those commands to your view, because they are a property.
You can implement ICommand this way - and this is a very common way of implementing ICommand. That being said, you still need to make MyCommand a property on the ViewModel in order to bind to it.