Issue
Currently I got a problem similiar to this
How can I stop a Toggled Event on a switch from being fired as a page is loaded?
Except my error is that when I toggle my switch it causes a infinity loop at the InitGroupMethod. It's because I'm changing the toggled event programmatically during this. Which triggers the toggleEvent again. What I want to happen is that when the category is disabled, all bottom categories will no longer be added and the page will be refreshed.
Currently the load correctly when opening the page, and if you save the list and then revisit it. But can't get the view to update when the switch is toggled withoutinfinity loop.
Image here https://gyazo.com/eedd4ab2ab3cd892ef57cd2d245d7dd1?token=d39388a4b5b726f6c5e2f44219dd4b6f
How do I get the view to update? I've tried to cause a custom switchcell and desubb from the toggleevent before changing this, but couldn't access the x:name due to it being a list. I've tried turning it into a switchcell too.xa
The list of 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();
}
}
}
The 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();
}
The Page
<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>
Solution
When writing a setter for a property which invokes PropertyChanged, guard the actual update and signaling of the event:
public bool IsEnabledBrand
{
get => isEnabledBrand;
set
{
if (isEnabledBrand != value)
{
isEnabledBrand = value;
NotifyPropertyChanged();
}
}
}
The whole point is that you don't want to raise the OnPropertyChanged event unless the property did change. There isn't quite enough of your code here to know if this is the problem, but it is worth keeping this design point in mind, as it can avoid problems.
Answered By - DavidS
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.