No... I think you can still have the strongly typed repository in the VM base.
public class VMBase<DataType, RepositoryType>: INotifyPropertyChanged
where DataType: DataObjectBase,
RepositoryType: IRepository<DataType>
{
private readonly RepositoryType _Repository;
public VMBase(RepositoryType repository)
{
_Repository = repository;
}
// some accessors for commonly used repository operations...
protected IQueryable<DataType> GetAllObjects()
{
return _Repository.GetAll();
}
// allow access to 'private' repository, without the caller having
direct access to the field...
protected void AccessRepository(Action<RepositoryType> repositoryAction)
{
repositoryAction(_Repository);
}
...
protected void OnPropertyChanged<T>(Expression<Func<T>> propertyAccessor)
{
// crack the property name from the expression and use it to fire
the PropertyChanged event.
}
}
public class BooksRepository: BaseRepository<Book>
{
public IQueryable<Book> GetBooksBySubjectFilter(string subjectFilter)
{
...
}
}
public class BooksVM: VMBase<Book, BooksRepository>
{
public BooksVM(BooksRepository repository)
: base(repository)
{
}
public string SubjectFilter
{
get { return _SubjectFilter; }
set
{
if(_SubjectFilter == value)
return;
_SubjectFilter = value;
_RefreshBooksList();
OnPropertyChanged(() => SubjectFilter);
}
}
private void _RefreshBooksList()
{
IQueryable<Book> booksList;
AccessRepository(r => booksList =
r.GetBooksBySubjectFilter(_SubjectFilter));
// ... do something to put booksList in a UI accessable
collection (ObservableCollection, etc.)
}
}
... yada yada yada...
get the idea?
On Wed, Mar 3, 2010 at 10:56 PM, Erick Thompson
<[email protected]> wrote:
> Amen to the VM/Control separation. I'm working with some existing code, so I
> don't have as much latitude as I'd like, but in my mind, the control should
> contain rendering code only (when the available UI widgets are lacking, for
> animation, etc). The ViewModel should contain all the logic/collections/etc
> for the control. With SL4 and commands, we are able to get a lot closer to
> that goal. I hope we're all the way there soon.
> If I have the generic parameter on the base class (I assume you mean base
> ViewModel), doesn't that imply that I then have to pass an untyped query to
> the repository? Then do a Cast<DataObject> operator on the way back (if
> needed)? I can't see any technical reason that it wouldn't work, but it
> seems dangerous somehow. Have you used a purely non-generic repository style
> system before? Any problems?
>
> Thanks, this has been extremely valuable!
>
> Erick
> On Wed, Mar 3, 2010 at 10:39 PM, Kelly Leahy <[email protected]>
> wrote:
>>
>> Actually, I think in that case your best bet is to have the generic
>> parameter on the base class. Why is it that you don't like that?
>>
>> Glenn's project that I was referring to is a side project, AFAIK, that
>> he was working on for binding using a fluent interface in code, rather
>> than specifying your bindings in XAML. AFAIK, it's still in the
>> "exploratory" stages, but I'm sure he'd love to talk about it with you
>> if he has time.
>>
>> I think the control shouldn't have any of this stuff in it, though.
>> It seems to me that the control code should be empty if at all
>> possible. All of the "view" logic should be in the VM. I don't take
>> as strong a view of the VM/M separation as some people do. In my
>> opinion it's ok to have a lot of code in the VM, so long as that
>> aligns with your testing needs and goals. Our issue right now is that
>> it doesn't ;)
>>
>> Kelly
>>
>> On Wed, Mar 3, 2010 at 10:31 PM, Erick Thompson
>> <[email protected]> wrote:
>> > Kelly,
>> >
>> > Thanks for the great response. I agree with your comments about
>> > inheritance
>> > (it is usually ugly). I love the idea about making the interface
>> > non-generic
>> > and moving the generic parameter to the method. One key detail that I
>> > forgot
>> > to mention is that this is a platform, and not an application, hence my
>> > inability to know what T is.
>> >
>> > I completely agree about keeping very little code in the ViewModel
>> > (except
>> > for UI specific code). My ultimate goal is to have a 100 level
>> > programmer be
>> > able to create a new ViewModel with very little knowledge of how it
>> > works,
>> > and do most of the presentation customization via XAML. The base VM
>> > contains
>> > all the plumbing to actually make things happen, and the derived VM is
>> > the
>> > one used by the dev. They would be expected to write something like the
>> > following.
>> >
>> > class MyDataObjectViewModel : FooViewModel {
>> > public override IQueryable<DataObject> Query(IQueryable<DataObject>
>> > basequery) {
>> > var query = from d in basequery
>> > select d; // or some other LINQ query)
>> >
>> > return base.Query(query);
>> > }
>> > }
>> >
>> > The base ViewModel actually handles the population and management of the
>> > items in the resulting collection (which the UI/Control binds to in a
>> > non-generic way). If I'm not mistaken, having the generic parameter on
>> > the
>> > method should work for this. I'll have to try it out in the morning.
>> >
>> > Aside from that, do you see a better way to do this? I generally don't
>> > like
>> > inheritance, but it seems like a good way to keep the messy details away
>> > from the end user/dev.
>> >
>> > Also, as an aside, which project of Glenn's are you referring to? It
>> > sounds
>> > interesting...
>> >
>> > Thanks,
>> > Erick
>> > On Wed, Mar 3, 2010 at 8:24 PM, Kelly Leahy <[email protected]>
>> > wrote:
>> >>
>> >> If we take a step back, and think about what you're saying, I think
>> >> you'll realize it doesn't make sense.
>> >>
>> >> It sounds like you're saying you want to have some generic object that
>> >> you hold onto in your class but you don't want to know what the type
>> >> of that object is. However, you want to be able to write code that
>> >> uses that object. There's not any sensible way that the compiler
>> >> could type-check your code without knowing what T is, which is why you
>> >> either need to specify a value of T in your field (i.e. bind the
>> >> parameter to a type), or you need to make T a generic parameter of
>> >> your type (i.e. leave it as an 'open' generic and 'provide' the T from
>> >> the use site of your class).
>> >>
>> >> The thing I'm not really getting is why the control author cares what
>> >> T is. It seems to me that if you're doing VM / PM pattern well, you
>> >> should be striving to have very little (if any) code in your controls,
>> >> and all of the interaction should be through bindings to the VM (which
>> >> are - by definition - untyped, though if you use something like the
>> >> binding frameworks that Glenn has been trying to build, you'll see
>> >> that you can use stronger typing in your bindings).
>> >>
>> >> What you can do, and I've done this in the past, is not make the
>> >> repository generic, but rather make its methods generic (i.e.
>> >> Query<T>(...) instead of IRepository<T>::Query(...)) but this won't
>> >> allow you to resolve different repositories by type from the IoC
>> >> container.
>> >>
>> >> The other thing I'd ask yourself is whether inheritance is the right
>> >> solution to your problem. In nearly every case in my past that I
>> >> thought it was, I turned out to be wrong. You might also think about
>> >> whether the type of the repository is important to be in a base class,
>> >> or whether you can get the same effect by having the base class be
>> >> abstract, providing a few methods to 'hook' into the derived class
>> >> implementations, and then you can have the type parameter on the base
>> >> class and have the deriving class provide the "T" when it derives. In
>> >> other words, you could make:
>> >>
>> >> public class FooContainerControl: ContainerControlBase<Foo> { ... }
>> >>
>> >> We do this a lot in our UI code (though we do it with the PMs, not the
>> >> controls, I personally hate base classes for controls - it never works
>> >> out well, we use interfaces exclusively for them). For instance, we
>> >> have a:
>> >>
>> >> public class EditorGridPresentationModelBase<T> where T: IItemCore,
>> >> class
>> >> { ... }
>> >>
>> >> and then for Table and Variable (both IItemCore implementers), we have
>> >>
>> >> public class EditorGridPresentationModel:
>> >> EditorGridPresentationModelBase<Table>
>> >> { ... }
>> >> (in the Tables namespace), and
>> >>
>> >> public class EditorGridPresentationModel:
>> >> EditorGridPresentationModelBase<Variable>
>> >> { ... }
>> >> (in the Input namespace).
>> >>
>> >> Kelly
>> >>
>> >> On Wed, Mar 3, 2010 at 4:10 PM, Erick Thompson
>> >> <[email protected]>
>> >> wrote:
>> >> > I have run into a situation where I can't see any good solutions, and
>> >> > I'm
>> >> > hoping someone has run into a similar situation.
>> >> >
>> >> > I have a generic IRepository<T> interface which is used for loading
>> >> > data
>> >> > from a store. I have the generic parameter as I want to allow typed
>> >> > queries
>> >> > (the queries will end up hitting a ANDS service). I want to use
>> >> > classes
>> >> > implementing interface this in custom controls and ModelViews in a
>> >> > Silverlight 4 application.
>> >> >
>> >> > The problem is that you can't have a generic interface in a class
>> >> > without
>> >> > having a generic type on the class.
>> >> >
>> >> > public class ControlBase {
>> >> > protected IRepository<T> _repository;
>> >> > }
>> >> >
>> >> > will not compile. As this is a base class, I can't specify the T
>> >> > unless
>> >> > I use a inherited base DataClass. I would like to use POCOs if
>> >> > possible.
>> >> >
>> >> > In the fantasy world in my head, I would simply make the base class
>> >> > generic,
>> >> > and Bob's your uncle. However, I want these classes to be easily
>> >> > consumed in
>> >> > XAML, which doesn't have a good way to instantiate a generic type.
>> >> >
>> >> > What I ultimately want is for the user to be able to create the
>> >> > control/form
>> >> > (bound to ModelView) without a generic type, but that the data access
>> >> > occurs
>> >> > in a typed way. For example:
>> >> >
>> >> > public class CoolControl : ControlBase {
>> >> > public CoolControl() {
>> >> > _repository = IoC.Resolve<IRepository<SomeConcreteDataType>>();
>> >> > }
>> >> >
>> >> > public LoadData () {
>> >> > // do some typed IQueryable stuff on repository
>> >> > }
>> >> > }
>> >> >
>> >> > With this, the user can specify the control/ViewModel in XAML, and
>> >> > the
>> >> > control/ViewModel author gets the benefit of typing.
>> >> >
>> >> > Is there any good way to do this or I am stuck?
>> >> >
>> >> > Thanks,
>> >> > Erick
>> >> >
>> >> >
>> >> > --
>> >> > You received this message because you are subscribed to the Google
>> >> > Groups
>> >> > "Seattle area Alt.Net" group.
>> >> > To post to this group, send email to [email protected].
>> >> > To unsubscribe from this group, send email to
>> >> > [email protected].
>> >> > For more options, visit this group at
>> >> > http://groups.google.com/group/altnetseattle?hl=en.
>> >> >
>> >>
>> >> --
>> >> You received this message because you are subscribed to the Google
>> >> Groups
>> >> "Seattle area Alt.Net" group.
>> >> To post to this group, send email to [email protected].
>> >> To unsubscribe from this group, send email to
>> >> [email protected].
>> >> For more options, visit this group at
>> >> http://groups.google.com/group/altnetseattle?hl=en.
>> >>
>> >
>> > --
>> > You received this message because you are subscribed to the Google
>> > Groups
>> > "Seattle area Alt.Net" group.
>> > To post to this group, send email to [email protected].
>> > To unsubscribe from this group, send email to
>> > [email protected].
>> > For more options, visit this group at
>> > http://groups.google.com/group/altnetseattle?hl=en.
>> >
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "Seattle area Alt.Net" group.
>> To post to this group, send email to [email protected].
>> To unsubscribe from this group, send email to
>> [email protected].
>> For more options, visit this group at
>> http://groups.google.com/group/altnetseattle?hl=en.
>>
>
> --
> You received this message because you are subscribed to the Google Groups
> "Seattle area Alt.Net" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected].
> For more options, visit this group at
> http://groups.google.com/group/altnetseattle?hl=en.
>
--
You received this message because you are subscribed to the Google Groups
"Seattle area Alt.Net" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/altnetseattle?hl=en.