如何解决如何从 ContentView 设置和获取在 ViewModel 中设置的属性
我有一个包含 ContentPage
的 CarouselView
。内容页面有 1 个列表属性 (ActivityData
),用作 ItemSource
。
ContentPage 使用 ItemTemplate
(ContentView
) 来显示不同的元素。此 ContrentView 包含在“main”属性中定义的属性; ActivityData
。
我想要实现的是以下内容,在我的 ContentView 中有一个卡片列表。此列表的 ItemSource 是 List 属性“LocationFloors
”,此属性包含在 ContentPage 的 ActivityData
中定义的 viewmodel
属性中。
我已经设置了一个 TapGestureRecognizer
事件来捕捉列表卡片上的 'tap' 事件。发生这种情况时,被点击的卡片应将其背景更改为红色,而列表中的所有其他卡片应将背景更改为蓝色。
我已经进行了一些设置,但是我在如何设置 LocationFloors
项的值的同时还触发了 NotifyPropertyChanged
事件以更改 UI 时遇到了问题。
NotifyPropertyChanged
现在在 viewmodel
本身中实现,但只会在我设置/更改 ActivityData
属性时触发。这是否意味着我必须直接在 LocationFloor
属性中更改 ActivityData
项?
如何从我的 ContentView 访问(获取/设置)在我的 viewmodel 中定义的 ActivityData
属性?
ContentView 代码:
public partial class PCSActivityOverviewTemplate : ContentView
{
public PCSActivityOverviewTemplate()
{
InitializeComponent();
}
private void OnTapGestureRecognizerTapped(object sender,EventArgs args)
{
var model = ((CardView)sender).BindingContext as ActivityFloor;
if(model.IsSelected == false)
{
model.IsSelected = true;
// Not triggering PropertyChanged...
}
}
}
视图模型:
public class ActivityOverviewviewmodel : ObservableObject
{
private List<ActivityLocation> activityData;
private readonly IRoutingService _routingService;
// The dataSource
public List<ActivityLocation> ActivityData
{
get { return activityData; }
set { SetProperty(ref activityData,value); }
}
public ActivityOverviewviewmodel(IRoutingService routingService = null)
: base(listenCultureChanges: true)
{
_routingService = routingService ?? Locator.Current.GetService<IRoutingService>();
LoadData();
}
private async void LoadData()
{
// Set DataSource of Page
var _activitiesData = await App.Database.GetActivityDataAsync(DateTime.UtcNow);
ActivityData = _activitiesData;
}
}
ActivityData 列表模型:
public class ActivityLocation
{
public int LocationId { get; set; }
.. few more properties
public List<ActivityFloor> LocationFloors { get; set; }
}
public class ActivityFloor
{
public int FloorId { get; set; }
.. some other properties
public bool IsSelected { get; set; } // property with which the Backgroundcolor of a Card should change.
}
解决方法
您可以使用 ICommand 然后可以在 ViewModel 中获取/设置 ActivityData
。
例如:
<TapGestureRecognizer
Command="{Binding TapCommand}"
CommandParameter="{Binding Source={x:Reference Item},Path=BindingContext}" />
//Item is the x:Name of the Root Layout (such as ListView Cell's ItemTemplate)
然后在 View Model 中可以得到:
public ICommand TapCommand
{
get
{
return new Command((e) =>
{
var item = (e as ActivityLocation);
item.backgroundcolor = ...
// logic on item
// Here data is ActivityLocation
foreach (var otheritem in ActivityData)
{
if(item.name == otheritem.name){
// do nothing
}else{
otheritem.backgroundcolor = ...
}
}
}
}
================================更新======== ==============================
从共享示例中,DemoTestTemplate 将不需要此处的可绑定属性:
public partial class DemoTestTemplate : ContentView
{
}
及其Xaml代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<ContentView
x:Class="TestDemoAPP.DemoTestTemplate"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<ContentView.Content>
<Grid>
<Label BackgroundColor="{Binding LabelColor}"
HeightRequest="100"
HorizontalOptions="Center"
HorizontalTextAlignment="Center"
Text="Hello Sir,please click me"
TextColor="White"
VerticalOptions="Center"
VerticalTextAlignment="Center"
WidthRequest="200">
</Label>
</Grid>
</ContentView.Content>
</ContentView>
并且你需要修改ActivityModel模型如下:
public class ActivityLocation: INotifyPropertyChanged
{
public List<ActivityLocation> activityLocations { set; get; }
public int LocationId { get; set; }
public string LocationName { get; set; }
public List<ActivityFloor> CurrentFloors { get; set; }
private Xamarin.Forms.Color labelColor;
public Xamarin.Forms.Color LabelColor
{
set
{
if (labelColor != value)
{
labelColor = value;
OnPropertyChanged("LabelColor");
}
}
get
{
return labelColor;
}
}
public ICommand TapCommand
{
get
{
return new Command((e) =>
{
var item = (e as ActivityLocation);
item.LabelColor = Xamarin.Forms.Color.Red;
// logic on item
// Here use messagecenter to ViewModel
MessagingCenter.Send<object,ActivityLocation>(this,"ColorChange",item);
});
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));
}
}
public class ActivityFloor
{
public int FloorId { get; set; }
public string FloorName { get; set; }
}
然后将DemoTestViewModelViewModel修改如下:
public class DemoTestViewModel : ObservableObject
{
public DemoTestViewModel()
{
LoadData();
}
private List<ActivityLocation> activityData;
public List<ActivityLocation> ActivityData
{
get { return activityData; }
set { SetProperty(ref activityData,value); }
}
private int _position;
public int Position
{
get { return _position; }
set { SetProperty(ref _position,value); }
}
private async void LoadData()
{
// SEEDING TEST DATA (2 differtent locations,5 floors each)
// Initialize Floors
var activityFloors_location1 = new List<ActivityFloor>
{
new ActivityFloor { FloorId = 1,FloorName = "(Location 1) Floor 1" },new ActivityFloor { FloorId = 2,FloorName = "(Location 1) Floor 2" },new ActivityFloor { FloorId = 3,FloorName = "(Location 1) Floor 3" },new ActivityFloor { FloorId = 4,FloorName = "(Location 1) Floor 4" },new ActivityFloor { FloorId = 5,FloorName = "(Location 1) Floor 5" }
};
var activityFloors_location2 = new List<ActivityFloor>
{
new ActivityFloor { FloorId = 1,FloorName = "(Location 2) Floor 1" },FloorName = "(Location 2) Floor 2" },FloorName = "(Location 2) Floor 3" },FloorName = "(Location 2) Floor 4" },FloorName = "(Location 2) Floor 5" }
};
// Initialize Locations / merge data
var activityLocations = new List<ActivityLocation>
{
new ActivityLocation {
LocationId = 1,LocationName = "Location 1",CurrentFloors = activityFloors_location1,LabelColor = Color.Blue
},new ActivityLocation
{
LocationId = 2,LocationName = "Location 2",CurrentFloors = activityFloors_location2,LabelColor = Color.Blue
}
};
// Set ListSource for ContentPage's CarouselView
try
{
activityData = activityLocations;
}
catch (Exception ex)
{
throw;
}
MessagingCenter.Subscribe<object,(sender,arg) =>
{
foreach(var item in activityData)
{
if(arg.LocationId == item.LocationId)
{
//do nothing
}
else
{
item.LabelColor = Color.Green;
}
}
});
}
}
现在回到DemoTestPage页面修改Xaml代码如下:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="TestDemoAPP.Views.DemoTestPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TestDemoAPP"
xmlns:vm="clr-namespace:TestDemoAPP.ViewModels">
<ContentPage.BindingContext>
<vm:DemoTestViewModel />
</ContentPage.BindingContext>
<ContentPage.Content>
<Grid>
<CarouselView
x:Name="carousel"
HorizontalScrollBarVisibility="Never"
IndicatorView="indicatorView"
IsScrollAnimated="False"
ItemsSource="{Binding ActivityData}"
Position="{Binding Position,Mode=TwoWay}"
VerticalOptions="FillAndExpand">
<CarouselView.ItemTemplate>
<DataTemplate>
<Frame x:Name="Item" Style="{StaticResource CarouselWorkaround}">
<local:DemoTestTemplate>
<local:DemoTestTemplate.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}"
CommandParameter="{Binding Source={x:Reference Item},Path=BindingContext}" />
</local:DemoTestTemplate.GestureRecognizers>
</local:DemoTestTemplate>
</Frame>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
<IndicatorView
x:Name="indicatorView"
Padding="0,30"
IndicatorColor="{DynamicResource TranslucidBlack}"
SelectedIndicatorColor="{DynamicResource BaseTextColor}"
VerticalOptions="Start" />
</Grid>
</ContentPage.Content>
</ContentPage>
然后你会看到效果:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。