简体   繁体   中英

Should ViewModels inherit other ViewModels in Xamarin.Forms?

Should ViewModels inherit other ViewModels ?

I have a MerchandiserViewModel that contains the basic properties and database functions for a Merchandiser model.

The MerchandiserViewModel has a SelectedMerchandiser property that holds the selected Merchandiser from the ItemSelected in a ListView

MerchandiserViewModel.cs

public MerchandiserViewModel : INotifyPropertyChanged
{
    // Property to hold the selected Merchandiser
    // Generally I would make this static but then I can't bind the property
    public Merchandiser SelectedMerchandiser {get; set;}

    // Other logic...

}

The MerchandiserViewModel is instantiated as a Static Resource in App.xaml so that I only have one instance of the view model.

App.xaml

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MobileApp.App"
             xmlns:ViewModels="clr-namespace:MobileApp.ViewModels">
    <Application.Resources>
        <ViewModels:MerchandiserViewModel x:Key="MerchandiserViewModel" />
        <ViewModels:MerchandiserProfileViewModel x:Key="MerchandiserProfileViewModel" />
    </Application.Resources>
</Application>

For each View related to a Merchandiser eg MerchandiserProfile , EditProfile etc. I create a new ViewModel and inherit the MerchandiserViewModel

MerchandiserProfileViewModel.cs inherits the MerchandiserViewModel

public class MerchandiserProfileViewModel : MerchandiserViewModel
{
    // Logic Specific to the Merchandiser Profile View
}

The problem is... when I create a new [Page]ViewModel and inherit the "MerchandiserViewModel" I receive the following error message.

错误信息

I think this may be because a new instance of the MerchandiserViewModel is created so I am not referencing the initial SelectedMerchandiser property.

This makes me think that inheriting ViewModels isn't a good idea?

How is this situation usually handled? Should I just jam all logic for each page/view into the one MerchandiserViewModel ? I want my code to be as clean an separated as possible, so would like to avoid this if possible.

AFTER THOUGHT Am I able to access the properties of the MerchandiserViewModel in static Resource in C#? this way I could pass the required properties to the new ViewModel without inheriting the MerchandiserViewModel ... keen to hear thoughts on this?

The MerchandiserViewModel has a SelectedMerchandiser property that holds the selected Merchandiser from the ItemSelected in a ListView

According to your description, you want to binding for ListView, for MerchandiserViewModel, you don't need to inherit other ViewModels, I suggest you can take a look the Model-View-ViewModel Pattern

I do one sample that binding ListView using MVVM, please take a look.

<StackLayout>
        <ListView
            x:Name="listview1"
            HasUnevenRows="True"
            ItemsSource="{Binding mers}"
            SelectedItem="{Binding selecteditem}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout>
                            <Label
                                FontSize="Large"
                                Text="{Binding Name}"
                                VerticalOptions="Center" />

                            <Label
                                FontSize="Small"
                                Text="{Binding PhoneNumber}"
                                VerticalOptions="Center" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>

The model class,contains some properties that binding to UI.

 public class Merchandiser
{
    public string Name { get; set; }    
    public string PhoneNumber { get; set; }
    
}

The MerchandiserViewmodel class, the view model implements properties and commands to which the view can data bind to, and notifies the view of any state changes through change notification events. The properties and commands that the view model provides define the functionality to be offered by the UI, but the view determines how that functionality is to be displayed.

 public class MerchandiserViewmodel:ViewModelBase
{
    public ObservableCollection<Merchandiser> mers { get; set; }
    private Merchandiser _selecteditem;
    public Merchandiser selecteditem
    {
        get { return _selecteditem; }
        set
        {
            _selecteditem = value;
            RaisePropertyChanged("selecteditem");
        }
    }
    public MerchandiserViewmodel()
    {
        mers = new ObservableCollection<Merchandiser>();
        getdata();
    }
    private void getdata()
    {
        for(int i=0;i<20;i++)
        {
            Merchandiser mer = new Merchandiser();
            mer.Name = "merchandiser "+i;
            mer.PhoneNumber = "123";
            mers.Add(mer);

        }
    }
}

The ViewModelBase is class that implementinf INotifyPropertyChanged interface, notify data changed. For MerchandiserViewmodel, the Selected Merchandiser(selecteditem) must implement INotifyPropertyChanged to notify data change when you selected item from ListView every time.

public class ViewModelBase : INotifyPropertyChanged
{
   
    public event PropertyChangedEventHandler PropertyChanged;

   
    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Binding ViewModel to ContentPage

 public partial class Page10 : ContentPage
{
    public Page10()
    {
        InitializeComponent();
        this.BindingContext = new MerchandiserViewmodel();
    }
}

Update:

If you want to navigate to detailed page when select ListView item, you can use constructor pass by value in ListView_ItemSelected event.

<StackLayout>
        <ListView
            x:Name="listview1" ItemSelected="listview1_ItemSelected" SelectionMode="Single"
            HasUnevenRows="True"
            ItemsSource="{Binding mers}"
            SelectedItem="{Binding selecteditem}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout>
                            <Label
                                FontSize="Large"
                                Text="{Binding Name}"
                                VerticalOptions="Center" />

                            <Label
                                FontSize="Small"
                                Text="{Binding PhoneNumber}"
                                VerticalOptions="Center" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>

  private async void listview1_ItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
        Merchandiser item = (Merchandiser)e.SelectedItem;
       await Navigation.PushAsync(new simplecontrol.Page29(item));
    }

Detailed Page:

<ContentPage.Content>
    <StackLayout>
        <StackLayout Orientation="Horizontal">
            <Label Text="Name: " />
            <Label
                FontSize="Large"
                Text="{Binding Name}"
                VerticalOptions="Center" />
        </StackLayout>
        <StackLayout Orientation="Horizontal">
            <Label Text="PhoneNumber: " />
            <Label
                FontSize="Small"
                Text="{Binding PhoneNumber}"
                VerticalOptions="Center" />
        </StackLayout>


    </StackLayout>
</ContentPage.Content>

public partial class Page29 : ContentPage
{
    public Page29(Merchandiser mer)
    {
        InitializeComponent();
        this.BindingContext = mer;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM