How Can I bind DataContext to a Generic ViewModel in XAML?

前端 未结 4 1879
夕颜
夕颜 2021-02-20 09:17

Suppose we have a generic View model like this:

public class MyViewModel : INotifyPropertyChanged where T : Class1
{
    private T _objectModel;
    pub         


        
相关标签:
4条回答
  • 2021-02-20 09:59

    You're not capable of setting a generic viewmodel in XAML because XAML requires known types at compile time.

    Dependency injection is your best bet

    public class MyControl : UserControl{     
       public MyControl(Object viewModel){    
          this.DataContext = viewModel;
       }
    }
    
    0 讨论(0)
  • 2021-02-20 10:00

    You could create a class that inherits from your generic ViewModel and use that

    public class PersonViewModel : ViewModel<Person>
    

    XAML:

    <UserControl.DataContext>
        <s:PersonViewModel/>
    </UserControl.DataContext>
    
    0 讨论(0)
  • 2021-02-20 10:11

    If your ViewModel is derived from a base class, let's say NonGenericViewModel then you can assign in code behind an object of type NonGenericViewModel to the DataContext. Using this way you still have the benefits of generics and the data binding will also work because the bindings will be made during runtime, no matter what type of object you assign to DataContext as long as it has properties, collections, etc required by your xaml controls.

    BaseViewModel<T> : NonGenericViewModel { ... }
    
    NonGenericViewModel : INotifyPropertyChanged { ... }
    

    And in code behind, in the ctor of your xaml.cs:

    NonGenericViewModel nonGenVM = new BaseViewModel<person>();
    this.DataContext = nonGenVM;
    

    Even this is correct and working:

    this.DataContext = new BaseViewModel<Person>();
    

    It depends if you need or not the class NonGenericViewModel in other places.

    0 讨论(0)
  • 2021-02-20 10:14

    When working with XAML, you cannot instantiate a view model with a generic parameter in XAML code.

    To work around this, you need to make use of inheritance, here's an example:

    public abstract class ViewModel<T>
    

    Usage:

    public class MovieViewModel : ViewModel<Movie>
    
    ...
    
    public class GenreViewModel : ViewModel<Genre>
    

    Creating a new class for each model seems to be a bit stupid, however this simply isn't true. By making the assumption that each view model contains one model, you've pretty much set yourself up for following this pattern in all view models, as your base view model enforces this constraint.

    I personally use the pattern of using a ViewModel<T> base class, where T is the model.

    It's certainly a good idea to keep the logic separated from your base view model. A view model for each model is in fact a very good pattern to implement.


    There is another way you can achieve what you're after, this is simply removing the generic from the view model base, consider the example:

    public class ViewModel
    {
        public object Model { get; protected set; }
    }
    

    Now, if you populate Model with let's say a Movie, then XAML will see it as a Movie, and not an object. Now this is pretty nifty as far as your XAML side goes, however, when you start working with this model in C#, then you're going to have all sorts of problems as you'll have to cast the object to whatever type you are using. So I wouldn't recommend this at all.


    Another method of getting around this would be to set the DataContext in code-behind, and if you're going to do that, then, well, only God can save you now. The main ideas around the MVVM design pattern is the separation of View logic and the Business layer (View Models), as soon as your View starts instantiating view models then that nice separation is lost.

    Now saying that, there's nothing stopping you from doing this, I've said this many times before. MVVM is a design pattern, not the law, if you want to set the DataContext in code-behind, then fair enough, however it's important that you are aware of the implications.

    0 讨论(0)
提交回复
热议问题