I need to know why the same item appearing three times in my page, is displayed only one time.
The item Achat de Voiture
which appears in Recents ... should also appear in Pinned and Need Attention ; it is not the case. Instead we have a blank space showing an empty item.
In my opinion it is because the same View-model is re-used for three views BUT is this a problem ?
UPDATE
About the code - The View Model code could be too long to post and the XAML code is partially from custom Listview (from another assembly)
Info which could help - The app have been working perfectly. This issue started recently, I believe one of these actions I recently made could be a cause:
- I changed my Firebase library
- I changed my local database library from Lex.db to LiteDB
- I updated my Xamarin.Forms package
- Yesterday I updated Win10
I hope this will help
UPDATE 2 (code)
XAML code of the ItemTemplate
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<StackLayout Grid.Column="0" Orientation="Horizontal">
<Label Text="{Binding Name}"
VerticalOptions="Center"
LineBreakMode="TailTruncation" />
<Label Text="{Binding ContactName}"
VerticalOptions="Center"
LineBreakMode="TailTruncation"
TextColor="{StaticResource secondary_text}">
<Label.IsVisible>
<OnIdiom x:TypeArguments="x:Boolean" Desktop="True" Tablet="True" TV="True" Phone="False" />
</Label.IsVisible>
</Label>
<baseView:FALabel Icon="FACalendarCheckO"
IsVisible="{Binding HasDue}"
TextColor="{StaticResource secondary_text}"
VerticalOptions="Center" />
<Label Text="{Binding FormattedDueDateAgo}"
IsVisible="{Binding HasDue}" FontAttributes="Italic"
LineBreakMode="HeadTruncation"
HorizontalOptions="FillAndExpand"
TextColor="{StaticResource secondary_text}"
VerticalOptions="Center" />
<baseView:FALabel Icon="{Binding EmotionIcon}"
TextColor="{Binding EmotionColor}"
BackgroundColor="Transparent"
IsVisible="{Binding HasEmotion}"
VerticalOptions="Center" HorizontalOptions="EndAndExpand" />
</StackLayout>
<Label Grid.Column="1" Text="{Binding DisplayAmountWithCurrency}"
TextColor="{Binding DisplayAmountTextColor}"
HorizontalOptions="End"
VerticalOptions="Center"
LineBreakMode="NoWrap" />
<BoxView Grid.Column="2" BackgroundColor="{Binding DueAmountTextColor}" HorizontalOptions="FillAndExpand" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
I Set the BindingContext
//I made the mothod async to avoid the page to freeze the second time it is instantiated
protected async override void OnAppearing()
{
base.OnAppearing();
if(BindingContext == null)
{
HVM = new HomePageVM();
BindingContext = HVM;
}
if (CurrentCount != Main.API.DebtsDB.Entries.Count)
{
CurrentCount = Main.API.DebtsDB.Entries.Count;
var l = Main.API.DebtsDB.Entries.ToList();
l.Sort((x, y) => (y.Modified.CompareTo(x.Modified) * 1024) + (x.IsFather.CompareTo(y.IsFather) * -1));
var Pending = new HomeDataGroup(l.Where((d) => d.IsNormalDebt && !d.StatusIgnored && !d.IsFather && !d.StatusValidated && d.HasDue && Math.Abs((d.DueDate - Core.Main.Now).TotalDays) < 90))
{
Title = "Close (90 days)",
Icon = FontIcon.FACalendar,
ShortTitle = "C",
};
var Pinned = new HomeDataGroup(l.Where((d) => d.IsNormalDebt && (d.PinnedUp || d.PinnedUpPlus)))
{
Title = "Pinned",
Icon = FontIcon.FAThumbTack,
IconColor = (Color)Application.Current.Resources["pinned_color"],
ShortTitle = "P",
};
var Attention = new HomeDataGroup(l.Where(d => d.IsNormalDebt && d.EmotionWarning))
{
Title = "Need Attention",
Icon = Cash.GetEmotionIcon(BaseEmotion.Warning),
IconColor = Cash.GetEmotionColor(BaseEmotion.Warning),
ShortTitle = "A",
};
var NotValidated = new HomeDataGroup(l.Where(d => d.IsNormalDebt && !d.StatusIgnored && !d.IsFather && !d.HasDue && !d.StatusValidated))
{
Title = "Awaiting Confirmation",
Icon = FontIcon.FACheck,
IconColor = (Color)Application.Current.Resources["pinned_color"],
ShortTitle = "C",
};
var Recents = new HomeDataGroup(l.Where((d) => d.IsNormalDebt && (Main.Now - d.ModifiedDate).Days < 14))
{
Title = "Recents (2 weeks ago)",
Icon = FontIcon.FAClockO,
ShortTitle = "R",
};
var ls = new List<HomeDataGroup>();
if (Pinned.Count > 0)
ls.Add(Pinned);
if (Pending.Count > 0)
ls.Add(Pending);
if (Attention.Count > 0)
ls.Add(Attention);
if (NotValidated.Count > 0)
ls.Add(NotValidated);
if (Recents.Count > 0)
ls.Add(Recents);
await Task.Delay(200); // The page was freezing without this
HVM.HomeItems = ls;
}
}
DebtsDB
is a class I use to get Models and generate ViewModels
DebtsDB = new Core.DB.RunningDB<Cash, CashVM>();
public class RunningDB<T, T_VM> : IRunningDB<T>
where T : BaseHistory
where T_VM : BaseHistory, new()
{
public RunningDB()
{
Entries = new ObservableCollection<T_VM>();
CacheEntries = new Dictionary<string, T_VM>();
}
public RealtimeDatabase<T> DB => IDB as RealtimeDatabase<T>;
private IRealtimeDatabase IDB { get; set; }
public ObservableCollection<T_VM> Entries { get; set; }
public Dictionary<string, T_VM> CacheEntries { get; set; }
IDisposable Subscription;
public void Observe()
{
try
{
var a = (from tr in DB.AsObservable()
where !string.IsNullOrEmpty(tr.Key)
select new { tr }
);
Subscription = a.Subscribe(onNext: pair => Observe(pair.tr.Key, pair.tr.Object, Entries, CacheEntries));
}
catch (Exception ex)
{
Main.AppStatus.OnError(new ErrorData { Ex = ex, FuncName = "Observe" });
}
}
protected void Observe(string key, T o, Collection<T_VM> l, Dictionary<string, T_VM> cache)
{
try
{
Main.AppStatus.IsRefreshing = false;
if (o == null || o.StatusDeleted)
ObserveDeleted(key, l, cache);
else
ObserveUpdate(key, o, l, cache);
}
catch (Exception ex)
{
Main.AppStatus.OnError(new ErrorData { Ex = ex, FuncName = "Observe" });
}
}
protected async void ObserveUpdate(string key, T o, Collection<T_VM> l, Dictionary<string, T_VM> cache)
{
o.Key = key;
T_VM o_vm = BaseHistory.Create<T, T_VM>(o);
o_vm.Load();
if (!cache.ContainsKey(key))
{
cache[key] = o_vm;
await CrossCollection.Current.AddAsync(l, o_vm);
}
else
{
cache[key] = o_vm;
for (int j = 0; j < l.Count; j++)
{
if (l[j].Key == key)
{
await CrossCollection.Current.ReplaceAsync(l, j, o_vm);
break;
}
}
}
}
protected async void ObserveDeleted<B_VM>(string key, Collection<B_VM> l, Dictionary<string, B_VM> cache)
where B_VM : BaseHistory
{
if (cache.ContainsKey(key))
{
await CrossCollection.Current.RemoveAsync(l, cache[key]);
cache.Remove(key);
}
}
public async Task Pull()
{
await IDB.PullAsync();
}
}
The ViewModel
public class CashVM : Cash, IBasePicture, IBaseHistoryVM, ISelectable
{
public CashVM()
{
Main.AppStatus.PropertyChanged += Status_PropertyChanged;
}
public string DisplayDate => HasDue ? (char)FontIcon.FACalendarCheckO + " " + FormattedDueDate : FormattedStartDate;
public string DisplayAmount => CashExt.FormatAmmoutWithSign(Amount, StatusIgnored, StatusValidated);
public string DisplayBaseAmount => (BaseAmount != 0 && !this.DebtShouldSum() ?
(BaseAmount > 0 ? "+" : "-")
: "") + FormattedBaseAmount;
public string DisplayAmountWithCurrency => Core.Main.Setting.UserSetting.Currency.AmountWithCurrency(DisplayAmount);
public string DisplayBaseAmountWithCurrency => Core.Main.Setting.UserSetting.Currency.AmountWithCurrency(DisplayBaseAmount);
public Color DisplayAmountTextColor => StatusIgnored || !StatusValidated ?
(Color)Main.App.Resources["secondary_text"]
: AmountTextColor;
public Color DisplayBaseAmountTextColor => !this.DebtShouldSum() ?
(Color)Main.App.Resources["secondary_text"]
: BaseAmountTextColor;
public bool NeedValidation => !IsFather && !StatusIgnored && !StatusValidated;
public bool ContactVisible => !HasParentContact && !string.IsNullOrEmpty(ContactName);
public bool SubjectVisible => !HasParentSubject && !string.IsNullOrEmpty(Name);
public override void Load()
{
base.Load();
}
}