ViewModel 是否应该继承 Xamarin.Forms 中的其他 ViewModel? [英] Should ViewModels inherit other ViewModels in Xamarin.Forms?
问题描述
是否应该ViewModels
继承其他ViewModels
?
我有一个 MerchandiserViewModel
,其中包含 Merchandiser
模型的基本属性和数据库功能.
MerchandiserViewModel
有一个 SelectedMerchandiser
属性,它在 中保存了从
ItemSelected
选择的 Merchandiser
列表视图
MerchandiserViewModel.cs
public MerchandiserViewModel : INotifyPropertyChanged{//用于保存选定 Merchandiser 的属性//通常我会将其设为静态,但随后我无法绑定该属性public Merchandiser SelectedMerchandiser {get;放;}//其他逻辑...}
MerchandiserViewModel
在 App.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
,例如MerchandiserProfile
、EditProfile
等.我创建了一个新的 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屋!