微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何从 ContentView 设置和获取在 ViewModel 中设置的属性

如何解决如何从 ContentView 设置和获取在 ViewModel 中设置的属性

我有一个包含 ContentPageCarouselView内容页面有 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>

然后你会看到效果:

enter image description here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。