Xamarin Switch ToggleEvent导致循环

时间:2019-04-29 00:34:00

标签: c# xaml xamarin xamarin.forms

目前,我有一个与此类似的问题

How can I stop a Toggled Event on a switch from being fired as a page is loaded?

除了我的错误外,当我切换我的开关时,它会在InitGroupMethod处导致无限循环。这是因为我在此期间以编程方式更改了切换事件。再次触发toggleEvent。我想发生的是,当禁用类别时,将不再添加所有底部类别,并且将刷新页面。

当前在打开页面时正确加载,并且如果保存列表然后重新访问它。但是,当切换无穷大循环时,无法更新视图。

此处的图片https://gyazo.com/eedd4ab2ab3cd892ef57cd2d245d7dd1?token=d39388a4b5b726f6c5e2f44219dd4b6f

如何获取视图更新?我试图在更改此事件之前导致自定义切换单元和从toggleEvent取消订阅,但由于它是一个列表,因此无法访问x:name。我也尝试过将其转换为切换单元。xa

brandsviewmodel列表

     public class BrandViewModel : ObservableCollection<SubBrandViewModel>, INotifyPropertyChanged
                {
                    private bool isEnabledBrand;

                    public event PropertyChangedEventHandler PropertyChanged;

                    public string HouseCode { get; set; }

                    public List<SubBrandViewModel> SubBrands { get; set; }

                    public bool IsEnabledBrand
                    {
                        get => isEnabledBrand;
                        set
                        {
                            isEnabledBrand = value;
                            NotifyPropertyChanged();
                        }
                    }
            }

PageViewModel

              public ObservableCollection<Grouping<BrandViewModel, SubBrandViewModel>> GroupedItems { get; set; }

                public List<BrandViewModel> Categories { get; set; }

                public List<string> AllowedBrands { get; set; }

                public List<string> AllowedSubBrands { get; set; }


        public void ComputeUiBrandStatus()
                {
                    Dictionary<string, bool> tableWithStrings = new Dictionary<string, bool>();

                    foreach (string code in AllowedBrands)
                    {
                        if (!tableWithStrings.ContainsKey(code))
                        {
                            tableWithStrings.Add(code, true);
                        }
                    }

                    foreach (BrandViewModel category in Categories)
                    {
                        if (tableWithStrings.ContainsKey(category.HouseCode))
                        {
                            category.IsEnabledBrand = true;
                        }

                        if (category.SubBrands != null)
                        {
                            foreach (SubBrandViewModel subCategory in category.SubBrands)
                            {
                                if (tableWithStrings.ContainsKey(subCategory.Code))
                                {
                                    subCategory.IsEnabledSubBrand = true;
                                }
                            }
                        }
                    }
                }

         private void InitGrouppedData()
                {

                    GroupedItems.Clear();
                    var items = new ObservableCollection<Grouping<BrandViewModel, SubBrandViewModel>>();
                    foreach (BrandViewModel category in Categories)
                    {
                        List<SubBrandViewModel> subCategory = new List<SubBrandViewModel>();
                        if (category.SubBrands != null && category.IsEnabledBrand)
                        {
                            subCategory.AddRange(category.SubBrands);
                        }

                        Grouping<BrandViewModel, SubBrandViewModel> group = new Grouping<BrandViewModel, SubBrandViewModel>(category, subCategory);

                        items.Add(group);
                    }

                    GroupedItems = items;
                }


           private void OnToggleSwitch(object obj)
                {
                   RemoveOrAddSubBrands();
                }

页面

 <ListView
          ItemsSource="{Binding GroupedItems}"
          IsGroupingEnabled="True"
          GroupDisplayBinding="{Binding Key.HouseCode}"
          GroupShortNameBinding="{Binding Key.HouseCode}"
          HasUnevenRows="False"
          Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" HorizontalOptions="FillAndExpand" 
          SelectionMode="None">
            <ListView.GroupHeaderTemplate >
                <DataTemplate>
                    <ViewCell >
                        <FlexLayout Direction="Row" JustifyContent="SpaceBetween">

                            <FlexLayout.Triggers>
                                <DataTrigger TargetType="FlexLayout" Binding="{Binding Source={x:Reference SwitchParent}, Path=IsToggled}" Value="True">
                                    <Setter Property="BackgroundColor" Value="{StaticResource ThemeBkColor}" />
                                </DataTrigger>
                            </FlexLayout.Triggers>

                            <Label Text="{Binding Key.HouseCode}" VerticalOptions="Center" VerticalTextAlignment="Center" Margin="20,0,0,0" >
                                <Label.Triggers>
                                    <DataTrigger TargetType="Label" Binding="{Binding Source={x:Reference SwitchParent},Path=IsToggled}" Value="True">
                                        <Setter Property="TextColor" Value="White" />
                                    </DataTrigger>
                                </Label.Triggers>
                            </Label>

                            <Switch x:Name="SwitchParent" IsToggled="{Binding Key.IsEnabledBrand}" >
                                <Switch.Behaviors>
                                    <controls:EventToCommandBehavior EventName="Toggled" Command="{Binding Source={x:Reference BrandPage}, Path=ViewModel.SwitchToggledCommand}" CommandParameter="{Binding .}"/>
                                </Switch.Behaviors>
                            </Switch>
                        </FlexLayout>
                    </ViewCell>


                   </DataTemplate>
                </ListView.GroupHeaderTemplate>
      <ListView.ItemTemplate>
                        <DataTemplate>
                            <ViewCell >
                                <FlexLayout Direction="Row" JustifyContent="SpaceBetween" Margin="30,0,0,0">

                                    <FlexLayout.Triggers>
                                        <DataTrigger TargetType="FlexLayout" Binding="{Binding Source={x:Reference Switch}, Path=IsToggled}" Value="True">
                                                <Setter Property="BackgroundColor" Value="{StaticResource ThemeBkColor}" />
                                            </DataTrigger>
                                    </FlexLayout.Triggers>

                                    <Label Text="{Binding Code}" VerticalOptions="Center" VerticalTextAlignment="Center" Margin="20,0,0,0" >
                                        <Label.Triggers>
                                            <DataTrigger TargetType="Label" Binding="{Binding Source={x:Reference Switch},Path=IsToggled}" Value="True">
                                                <Setter Property="TextColor" Value="White" />
                                            </DataTrigger>
                                        </Label.Triggers>
                                    </Label>

                                    <Switch x:Name="Switch" IsToggled="{Binding IsEnabledSubBrand}" />

                                </FlexLayout>
                            </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>

2 个答案:

答案 0 :(得分:1)

在为调用PropertyChanged的属性编写设置器时,请保护事件的实际更新和信令:

                public bool IsEnabledBrand
                {
                    get => isEnabledBrand;
                    set
                    {
                        if (isEnabledBrand != value)
                        {
                            isEnabledBrand = value;
                            NotifyPropertyChanged();
                        }
                    }
                }

要点是,除非属性发生更改,否则您不希望引发OnPropertyChanged事件。您的代码不足以知道这是否是问题,但是值得牢记此设计要点,因为它可以避免出现问题。

答案 1 :(得分:1)

只要为我的特定循环开关问题添加解决方案,以防其他类似情况的人受益:

我只需要确保我的切换事件处理程序使用的是事件args,而不是IsToggled绑定变量。

更改自:

        async void ToggleFollow(object sender, ToggledEventArgs args) {
            if (viewModel.UserIsFollowingOwner) { 
                await viewModel.UnFollowOwner();
            } else {
                await viewModel.FollowOwner();
            }
        }

收件人:

        async void ToggleFollow(object sender, ToggledEventArgs args) {
            if (args.Value) { 
                await viewModel.FollowOwner();
            } else {
                await viewModel.UnFollowOwner();
            }
        }