ViewModel 是否应该继承 Xamarin.Forms 中的其他 ViewModel? [英] Should ViewModels inherit other ViewModels in Xamarin.Forms?

查看:38
本文介绍了ViewModel 是否应该继承 Xamarin.Forms 中的其他 ViewModel?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否应该ViewModels继承其他ViewModels?

我有一个 MerchandiserViewModel,其中包含 Merchandiser 模型的基本属性和数据库功能.

MerchandiserViewModel 有一个 SelectedMerchandiser 属性,它在 中保存了从 ItemSelected 选择的 Merchandiser列表视图

MerchandiserViewModel.cs

public MerchandiserViewModel : INotifyPropertyChanged{//用于保存选定 Merchandiser 的属性//通常我会将其设为静态,但随后我无法绑定该属性public Merchandiser SelectedMerchandiser {get;放;}//其他逻辑...}

MerchandiserViewModelApp.xaml 中被实例化为一个 Static Resource,因此我只有一个视图模型实例.>

App.xaml

<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"><应用程序.资源><ViewModels:MerchandiserViewModel x:Key=MerchandiserViewModel"/><ViewModels:MerchandiserProfileViewModel x:Key=MerchandiserProfileViewModel"/></Application.Resources></应用程序>

对于与销售商相关的每个 View,例如MerchandiserProfileEditProfile 等.我创建了一个新的 ViewModel 并继承了 MerchandiserViewModel

MerchandiserProfileViewModel.cs 继承了 MerchandiserViewModel

公共类 MerchandiserProfileViewModel : MerchandiserViewModel{//特定于 Merchandiser Profile View 的逻辑}

问题是...当我创建一个新的 [Page]ViewModel 并继承MerchandiserViewModel"时我收到以下错误消息.

我认为这可能是因为创建了 MerchandiserViewModel 的新实例,所以我没有引用初始的 SelectedMerchandiser 属性.

这让我觉得继承 ViewModels 不是一个好主意?

这种情况一般是怎么处理的?我应该将每个页面/视图的所有逻辑都塞进一个 MerchandiserViewModel 中吗?我希望我的代码尽可能干净和分离,因此希望尽可能避免这种情况.

经过深思熟虑我可以在 C# 的静态资源中访问 MerchandiserViewModel 的属性吗?这样我就可以在不继承 MerchandiserViewModel 的情况下将所需的属性传递给新的 ViewModel ......很想听到关于这个的想法吗?

解决方案

MerchandiserViewModel 有一个 SelectedMerchandiser 属性,该属性保存了 ListView 中 ItemSelected 中选定的 Merchandiser

根据你的描述,你要绑定ListView,MerchandiserViewModel,你不需要继承其他ViewModel,建议你看看模型-视图-视图模型模式

我做了一个使用 MVVM 绑定 ListView 的示例,请看一下.

<列表视图x:Name=listview1"HasUnevenRows="True"ItemsSource="{Binding mers}";SelectedItem="{Binding selecteditem}"><ListView.ItemTemplate><数据模板><ViewCell><堆栈布局><标签FontSize=大"文本={绑定名称}"VerticalOptions=中心"/><标签FontSize=小"文本={绑定电话号码}";VerticalOptions=中心"/></StackLayout></ViewCell></数据模板></ListView.ItemTemplate></ListView></StackLayout>

模型类,包含一些绑定到 UI 的属性.

 公共类 Merchandiser{公共字符串名称{获取;放;}公共字符串电话号码 { 获取;放;}}

MerchandiserViewmodel 类,视图模型实现视图可以数据绑定到的属性和命令,并通过更改通知事件通知视图任何状态更改.视图模型提供的属性和命令定义了 UI 提供的功能,但视图决定了该功能的显示方式.

 公共类 MerchandiserViewmodel:ViewModelBase{公共 ObservableCollectionmers { 得到;放;}私人跟单员_selecteditem;公共跟单员选定项目{得到 { 返回 _selecteditem;}放{_selecteditem = 值;RaisePropertyChanged("selecteditem");}}公共 MerchandiserViewmodel(){mers = new ObservableCollection();获取数据();}私有无效getdata(){for(int i=0;i<20;i++){采购员 mer = 新采购员();mer.Name = "商人"+i;mer.PhoneNumber = "123";mers.Add(mer);}}}

ViewModelBase 是实现 INotifyPropertyChanged 接口的类,通知数据发生变化.对于 MerchandiserView 模型,Selected Merchandiser(selecteditem) 必须实现 INotifyPropertyChanged 以在您每次从 ListView 中选择项目时通知数据更改.

公共类 ViewModelBase : INotifyPropertyChanged{公共事件 PropertyChangedEventHandler PropertyChanged;public void RaisePropertyChanged(string propertyName){PropertyChangedEventHandler 处理程序 = PropertyChanged;如果(处理程序!= null){handler(this, new PropertyChangedEventArgs(propertyName));}}}

将 ViewModel 绑定到 ContentPage

 公共部分类 Page10 : ContentPage{公共页面10(){初始化组件();this.BindingContext = new MerchandiserViewmodel();}}

更新:

如果要在选择 ListView 项时导航到详细页面,可以在 ListView_ItemSelected 事件中使用构造函数传递值.

<列表视图x:Name=listview1"ItemSelected="listview1_ItemSelected";选择模式=单"HasUnevenRows="True"ItemsSource="{Binding mers}";SelectedItem="{Binding selecteditem}"><ListView.ItemTemplate><数据模板><ViewCell><堆栈布局><标签FontSize=大"文本={绑定名称}"VerticalOptions=中心"/><标签FontSize=小"文本={绑定电话号码}";VerticalOptions=中心"/></StackLayout></ViewCell></数据模板></ListView.ItemTemplate></ListView></StackLayout>private async void listview1_ItemSelected(object sender, SelectedItemChangedEventArgs e){Merchandiser item = (Merchandiser)e.SelectedItem;等待 Navigation.PushAsync(new simplecontrol.Page29(item));}

详细页面:

<堆栈布局><StackLayout Orientation=水平"><标签文本=名称:"/><标签FontSize=大"文本={绑定名称}"VerticalOptions=中心"/></StackLayout><StackLayout Orientation=水平"><标签文本=电话号码:"/><标签FontSize=小"文本={绑定电话号码}";VerticalOptions=中心"/></StackLayout></StackLayout></ContentPage.Content>公共部分类 Page29 : ContentPage{public Page29(Merchandiser mer){初始化组件();this.BindingContext = mer;}}

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 e.g. 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;
    }
}

这篇关于ViewModel 是否应该继承 Xamarin.Forms 中的其他 ViewModel?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆