Numbers not updating on view and On Appearing not helpful - c#

I have method for deleting a word from a dictionary. Deleting works fine and when I debug the method I can see that the correct amount is being transferred to the UI however the UI doesn't update here I can see there is the correct amount
AmountOfWordsInDictionary = _allWordsOfUser?.Count ?? default;
It updates once I leave and come back. FYI my notify view works fine on any other part of my page, I have also tried on appearing but that is not very helpful
Can you please advise
public int AmountOfWordsInDictionary
{
set
{
_amountOfWordsInDictionary = value;
NotifyPropertyChanged(nameof(AmountOfWordsInDictionary));
}
get { return _amountOfWordsInDictionary; }
}
My method:
private async void RemoveWordFromUserDictionary()
{
if (!wordIsRemoving && !viewDisabled)
{
wordIsRemoving = true;
if (NetworkDelegate.IsOnline)
{
var wordRemovedApiResponse = await App.ApiFactory.RemoveWordFromUserDictionaryAsync(_word, LoggedUser.CurrentUser.Id);
if (wordRemovedApiResponse.ApiResponse == ApiResponse.Ok)
{
FindAnotherWordInDictionary();
_allWordsOfUser = App.ApiFactory.GetAllWordsOfUserLocal();
AmountOfWordsInDictionary = _allWordsOfUser?.Count ?? default;
}
else
{
NotificationService.ShowToast("something is wrong");
}
}
else
{
await App.ApiFactory.RemoveWordFromUserDictionaryLocalAsync(_word, LoggedUser.CurrentUser.Id);
FindAnotherWordInDictionary();
_allWordsOfUser = App.ApiFactory.GetAllWordsOfUserLocal();
**AmountOfWordsInDictionary** = _allWordsOfUser?.Count ?? default;
**// have also tried _amountOfWordsInDictionary**
}
wordIsRemoving = false;
}
}
My xaml :
<Label
Grid.Row="0"
Grid.Column="1"
Margin="0"
FontSize="15"
HorizontalOptions="End"
IsVisible="{grial:OnOrientationBool Default='true',
LandscapePhone='false'}"
Text="{Binding AmountOfWordsInDictionary,Mode=TwoWay}"
TextColor="{DynamicResource CircleActionButtonFlatTextColor}"
VerticalOptions="Start" />
public Dictionary()
{
InitializeComponent();
BindingContext = new DictionaryViewModel();
}

Related

Error This PlotModel is already in use by some other PlotView control in OxyPlot chart

I am using Xamarin.Forms OxyPlot Chart. I have a collectionview and in each collectionview item has an expander and inside each of those expanders is a PlotView
<CollectionView x:Name="Kids">
<CollectionView.ItemTemplate>
<DataTemplate>
<xct:Expander Tapped="Expander_Tapped" ClassId="{Binding rowNumber}">
<xct:Expander.Header>
<Frame Padding="0" CornerRadius="10" Margin="5" BackgroundColor="White" HasShadow="False">
<StackLayout>
<Grid BackgroundColor="#f8f8f8">
<StackLayout Padding="5" Orientation="Horizontal">
<Image x:Name="kidProfile" Source="{Binding image}" WidthRequest="75" HeightRequest="75" HorizontalOptions="Start" Aspect="AspectFill" />
<StackLayout Orientation="Vertical">
<Label Text="{Binding first_name}"></Label>
<StackLayout Orientation="Horizontal">
<Label Text="Grade: " FontSize="Small"></Label>
<Label Text="{Binding grade}" FontSize="Small"></Label>
</StackLayout>
</StackLayout>
</StackLayout>
<Image Margin="20" HorizontalOptions="End" Source="arrowDown.png" HeightRequest="15"></Image>
</Grid>
</StackLayout>
</Frame>
</xct:Expander.Header>
<oxy:PlotView Model="{Binding chart}" HeightRequest="200" WidthRequest="100" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
and I was assigning the PlotModel in my class
public class ReportsClass
{
public PlotModel chart
{
get
{
PlotModel model = new PlotModel();
CategoryAxis xaxis = new CategoryAxis();
xaxis.Position = AxisPosition.Bottom;
xaxis.MajorGridlineStyle = LineStyle.None;
xaxis.MinorGridlineStyle = LineStyle.None;
xaxis.MinorTickSize = 0;
xaxis.MajorTickSize = 0;
xaxis.TextColor = OxyColors.Gray;
xaxis.FontSize = 10.0;
xaxis.Labels.Add("S");
xaxis.Labels.Add("M");
xaxis.Labels.Add("T");
xaxis.Labels.Add("W");
xaxis.Labels.Add("T");
xaxis.Labels.Add("F");
xaxis.Labels.Add("S");
xaxis.GapWidth = 10.0;
xaxis.IsPanEnabled = false;
xaxis.IsZoomEnabled = false;
LinearAxis yaxis = new LinearAxis();
yaxis.Position = AxisPosition.Left;
yaxis.MajorGridlineStyle = LineStyle.None;
xaxis.MinorGridlineStyle = LineStyle.None;
yaxis.MinorTickSize = 0;
yaxis.MajorTickSize = 0;
yaxis.TextColor = OxyColors.Gray;
yaxis.FontSize = 10.0;
yaxis.FontWeight = FontWeights.Bold;
yaxis.IsZoomEnabled = false;
yaxis.IsPanEnabled = false;
ColumnSeries s2 = new ColumnSeries();
s2.TextColor = OxyColors.White;
s2.Items.Add(new ColumnItem
{
Value = Sunday,
Color = OxyColor.Parse("#02cc9d")
});
s2.Items.Add(new ColumnItem
{
Value = Monday,
Color = OxyColor.Parse("#02cc9d")
});
s2.Items.Add(new ColumnItem
{
Value = Tuesday,
Color = OxyColor.Parse("#02cc9d")
});
s2.Items.Add(new ColumnItem
{
Value = Wednesday,
Color = OxyColor.Parse("#02cc9d")
});
s2.Items.Add(new ColumnItem
{
Value = Thursday,
Color = OxyColor.Parse("#02cc9d")
});
s2.Items.Add(new ColumnItem
{
Value = Friday,
Color = OxyColor.Parse("#02cc9d")
});
s2.Items.Add(new ColumnItem
{
Value = Saturday,
Color = OxyColor.Parse("#02cc9d")
});
model.Axes.Add(xaxis);
model.Axes.Add(yaxis);
model.Series.Add(s2);
model.PlotAreaBorderColor = OxyColors.Transparent;
return model;
}
}
}
Now this works, but in the Expander when I expand an item the PlotView would not show, at all. So I changed my Class to use INotifyPropertyChanged
public class ReportsClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public PlotModel chart
{
get => _chart;
set
{
_chart = value;
if(_chart.PlotView == null && value.PlotView == null)
{
OnPropertyChanged("chart");
}
}
}
public PlotModel _chart;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
if(this.chart.PlotView == null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And in my code behind I use the expander's tapped method to populate the PlotView:
void Expander_Tapped(System.Object sender, System.EventArgs e)
{
if(expander != null)
{
expander.IsExpanded = false;
}
expander = sender as Expander;
int id = Convert.ToInt32(expander.ClassId);
ReportsClass item = newKidList[id];
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
if (item.chart == null)
{
PlotModel model = new PlotModel();
CategoryAxis xaxis = new CategoryAxis();
xaxis.Position = AxisPosition.Bottom;
xaxis.MajorGridlineStyle = LineStyle.None;
xaxis.MinorGridlineStyle = LineStyle.None;
xaxis.MinorTickSize = 0;
xaxis.MajorTickSize = 0;
xaxis.TextColor = OxyColors.Gray;
xaxis.FontSize = 10.0;
xaxis.Labels.Add("S");
xaxis.Labels.Add("M");
xaxis.Labels.Add("T");
xaxis.Labels.Add("W");
xaxis.Labels.Add("T");
xaxis.Labels.Add("F");
xaxis.Labels.Add("S");
xaxis.GapWidth = 10.0;
xaxis.IsPanEnabled = false;
xaxis.IsZoomEnabled = false;
LinearAxis yaxis = new LinearAxis();
yaxis.Position = AxisPosition.Left;
yaxis.MajorGridlineStyle = LineStyle.None;
xaxis.MinorGridlineStyle = LineStyle.None;
yaxis.MinorTickSize = 0;
yaxis.MajorTickSize = 0;
yaxis.TextColor = OxyColors.Gray;
yaxis.FontSize = 10.0;
yaxis.FontWeight = FontWeights.Bold;
yaxis.IsZoomEnabled = false;
yaxis.IsPanEnabled = false;
ColumnSeries s2 = new ColumnSeries();
s2.TextColor = OxyColors.White;
s2.Items.Add(new ColumnItem
{
Value = item.Sunday,
Color = OxyColor.Parse("#02cc9d")
});
s2.Items.Add(new ColumnItem
{
Value = item.Monday,
Color = OxyColor.Parse("#02cc9d")
});
s2.Items.Add(new ColumnItem
{
Value = item.Tuesday,
Color = OxyColor.Parse("#02cc9d")
});
s2.Items.Add(new ColumnItem
{
Value = item.Wednesday,
Color = OxyColor.Parse("#02cc9d")
});
s2.Items.Add(new ColumnItem
{
Value = item.Thursday,
Color = OxyColor.Parse("#02cc9d")
});
s2.Items.Add(new ColumnItem
{
Value = item.Friday,
Color = OxyColor.Parse("#02cc9d")
});
s2.Items.Add(new ColumnItem
{
Value = item.Saturday,
Color = OxyColor.Parse("#02cc9d")
});
model.Axes.Add(xaxis);
model.Axes.Add(yaxis);
model.Series.Add(s2);
model.PlotAreaBorderColor = OxyColors.Transparent;
item.chart = model;
}
return false;
});
}
However, eventually I will get this error:
This PlotModel is already in use by some other PlotView control
Now I understand that there is a one-to-one relation between the PlotView and its PlotModel, which gives us the error, so I have tried to do a check to see if PlotModel has a PlotView, but I am still getting this error.
I found this solution:
If you set the parent View of your OxyPlot to a DataTemplate that
creates a new OxyPlot each time then the OxyPlot cannot be cached. A
new PlotModel and PlotView is created each time and this error is
avoided (at least that seems to work for me, I am using CarouselView)
https://github.com/oxyplot/oxyplot-xamarin/issues/17
But I do not know how to do this for a collection view, any help would be much apperciated.
I also found this:
This is a very common issue of OxyPlot when it's used in MVVM. In
OxyPlot, the view and the model are 1-to-1 mapped, when a second view
is trying to bind the same PlotModel, you have the issue of "PlotModel
is already in use by some other PlotView control". On iOS, ListView's
cell will be re-created when it is scrolling. In this case, there will
be a newly created view trying to bind the same PlotModel, and then
you have the issue. On Android, I guess you will have the same issue
too. Try to put your phone from landscape to portrait, see if you have
the same issue. In Android, the view will be re-created completely
when the orientation is changed.
A quick fix is to break the MVVM design here a little bit. Don't
create the model in a separated place but create the model in the
view. So whenever a view is re-created by iOS or Android, a new model
is also re-created.
https://github.com/oxyplot/oxyplot-xamarin/issues/60
But I don't know how to apply this part:
A quick fix is to break the MVVM design here a little bit. Don't
create the model in a separated place but create the model in the
view. So whenever a view is re-created by iOS or Android, a new model
is also re-created.
See github ToolmakerSteve / repo OxyplotApp1, for working version.
"This PlotModel is already in use by some other PlotView control"
After various tests on iOS, I conclude that using (CollectionView or ListView) + Expander + Oxyplot on iOS is fundamentally not reliable.
Oxyplot seems to worsen known issues with Expander and CollectionView.
Therefore, the most important fix is to stop using these collection views. Replace use of CollectionView with:
<StackLayout Spacing="0" BindableLayout.ItemsSource="{Binding KidModels}">
<BindableLayout.ItemTemplate>
<DataTemplate>
For better performance, make this change, so each graph is only created the first time a user clicks a given item:
void Expander_Tapped(System.Object sender, System.EventArgs e)
{
// --- ADD THESE LINES ---
if (ReferenceEquals(sender, expander)) {
// User is tapping the existing expander. Don't do anything special.
return;
}
...
}
NOTE: Also fixes a problem where expander immediately closed again, if user tapped it three times in a row.
Faster appearance the first time each expander is clicked. Here are three alternatives. From fastest to slowest. Use the first, but if ever get a blank graph or other problem, switch to second. If second still has problems, switch to third - which is the original, though with a slightly shorter time delay:
if (item.Chart == null) {
PlotModel model = CreateReportChart(item);
Action action = () => {
item.Chart = model;
};
if (false) {
action();
} else if (true) {
Device.BeginInvokeOnMainThread(() => {
action();
});
} else {
Device.StartTimer(TimeSpan.FromSeconds(0.5), () => {
action();
return false;
});
}
}
OPTIONAL: To be sure expander animation doesn't cause a problem when used with Oxyplot.
If having problems that occur, but only "sometimes", try this, see if situation improves:
<xct:Expander AnimationLength="0" ...>
That should remove the animation.
You can remove tests such as if (_chart.PlotView == null && value.PlotView == null) from your OnPropertyChanged-related code. That is, ALWAYS do the OnPropertyChanged.
REASON: in the future you might wish to generate a modified plot because data changed, and the tests you have would prevent UI from seeing the change.

How to remove video black bands in videoView with LibVlcSharp?

when I play a video with video, it presents black bands in the top and bottom part of the video, like in image in the URL
https://imgur.com/a/JiUv8rt. I'd like to remove the bands and display just the video in an absolute layout. how can I reach my goal?
<pages:PopupPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:animations="clr-namespace:Rg.Plugins.Popup.Animations;assembly=Rg.Plugins.Popup"
xmlns:shared="clr-namespace:LibVLCSharp.Forms.Shared;assembly=LibVLCSharp.Forms"
x:Class="App.Pages.WebcamVideoPopUpPage"
BackgroundColor="Transparent">
<pages:PopupPage.Animation>
<animations:ScaleAnimation
PositionIn="Center"
PositionOut="Center"
ScaleIn="1.2"
ScaleOut="0.8"
DurationIn="400"
DurationOut="300"
EasingIn="SinOut"
EasingOut="SinIn"
HasBackgroundAnimation="True"/>
</pages:PopupPage.Animation>
<AbsoluteLayout x:Name="AbsoluteLayoutWebcam"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<shared:VideoView x:Name="VideoViewWebcam"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0, 0, 1, 1"
MediaPlayer ="{Binding MediaPlayer}"
MediaPlayerChanged ="VideoView_MediaPlayerChanged"/>
<Label x:Name="DescriptionWebcam"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0, 0, 1, .2"
HorizontalOptions="Fill"
VerticalOptions="Fill"
Text="{Binding InfoWebcam}"
FontSize="Large"
TextColor="White"/>
</AbsoluteLayout>
</pages:PopupPage>
UPDATE
I update at latest pre-release as #mtz suggested me, and I modified my code in the following way:
public partial class WebcamVideoPopUpPage : PopupPage
{
public WebcamVideoPopUpPage()
{
var vm = App.Locator.WebCamVideoVM;
this.BindingContext = vm;
InitializeComponent();
MediaPlayerWebcam.VideoView.MediaPlayerChanged += VideoView_MediaPlayerChanged;
MediaPlayerWebcam.MediaPlayer.AspectRatio = "FitScreen";
}
protected override void OnAppearing()
{
base.OnAppearing();
Messenger.Default.Send(new OnApperingVideoMessage());
}
private void VideoView_MediaPlayerChanged(object sender, LibVLCSharp.Shared.MediaPlayerChangedEventArgs e)
{
Messenger.Default.Send(new OnVideoViewInitializedMessage());
}
protected override void OnDisappearing()
{
base.OnDisappearing();
MediaPlayerWebcam.MediaPlayer.Stop();
MediaPlayerWebcam.MediaPlayer = null;
}
}
My xaml:
<AbsoluteLayout x:Name="AbsoluteLayoutWebcam"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<shared:MediaPlayerElement x:Name="MediaPlayerWebcam"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0, 0, 1, .4"
MediaPlayer ="{Binding MediaPlayer}"/>
<Label x:Name="DescriptionWebcam"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0, 0, 1, .2"
HorizontalOptions="Fill"
VerticalOptions="Fill"
Text="{Binding InfoWebcam}"
FontSize="Large"
TextColor="White"/>
</AbsoluteLayout>
My viewModel:
public class WebcamVideoViewModel : BaseViewModel
{
private LibVLC LibVLC { get; set; }
private bool IsLoaded { get; set; }
private bool IsVideoViewInitialized { get; set; }
private Media Media { get; set; }
private MediaPlayer _mediaPlayer;
public MediaPlayer MediaPlayer
{
get { return _mediaPlayer; }
set
{
_mediaPlayer = value;
OnPropertyChanged();
}
}
private string _InfoWebcam { get; set; }
public string InfoWebcam
{
get { return _InfoWebcam; }
set
{
_InfoWebcam = value;
OnPropertyChanged();
}
}
public WebcamVideoViewModel(INavigationService navigationService, IApiAutostradeManagerFactory apiAutostradeFactory) : base(navigationService, apiAutostradeFactory)
{
Messenger.Default.Register<InfoWebcamVideoMessage>(this, OnReceivedInfoWebcam);
Messenger.Default.Register<OnApperingVideoMessage>(this, OnAppearing);
Messenger.Default.Register<OnVideoViewInitializedMessage>(this, OnVideoViewInitialized);
Task.Run(Initialize);
}
private void Initialize()
{
Core.Initialize();
LibVLC = new LibVLC();
MediaPlayer = new MediaPlayer(LibVLC);
}
private async void OnReceivedInfoWebcam(InfoWebcamVideoMessage msg)
{
var response = await ApiManager.GetVideoWebcam(msg.Mpr, msg.Uuid);
if (response.IsSuccessStatusCode)
{
InfoWebcam = msg.T_Description_webcam;
var stream = await response.Content.ReadAsStreamAsync();
Media = new Media(LibVLC, stream);
Play();
}
}
public void OnAppearing(OnApperingVideoMessage msg)
{
IsLoaded = true;
}
public void OnVideoViewInitialized(OnVideoViewInitializedMessage msg)
{
IsVideoViewInitialized = true;
}
private void Play()
{
if (IsLoaded && IsVideoViewInitialized)
{
MediaPlayer.Play(Media);
}
}
}
Now i'm closer to solution because videoView is resizable with the button present at bootm, but I'd like to get at start the fill AspectRatio and I don't want anything expect the video(In other words, I'd want to remove seek bar and resize video button). Another problem is that after I close mediaPlayer, and I open again a new video, my app crashes. Any advice?
You need to change the aspect ratio to "fill the screen".
See how to here: https://github.com/videolan/libvlcsharp/blob/91b8f06ee1bedd9b3219a4e9ade0a9c44f59fda8/LibVLCSharp.Forms/Shared/PlaybackControls.xaml.cs#L926 or use the latest pre-release LibVLCSharp.Forms package that contains the MediaPlayerElement which has this feature built-in (soon in stable version).
What you just trying is to stretch the video. But remember it will effect video quality.
To remain simple, you can try this working and tested code:
MediaPlayerWebcam.MediaPlayer.AspectRatio = $"{MediaPlayerWebcam.Width.ToString()}:{MediaPlayerWebcam.Height.ToString()}";
MediaPlayerWebcam.Scale = 0;
My scenario is a fullscreen player, I do it with these codes refer to LibVLCSharp.Forms, hope it will be helpful. the code deal with fullscreen(commented) or fill screen with video.
public void PlayerFullScreen()
{
//restore
if (_isFullScreen)
{
RestoreDefaultWindowInfo();
_isFullScreen = false;
_mediaPlayer.Scale = _originalScale; //reset
_mediaPlayer.AspectRatio = _originalAspectRatio;
//Mouse.Capture(null);
playerBar.Visibility = Visibility.Visible;
}
else // fullscreen(stretch video)
{
this.WindowStyle = WindowStyle.None;
this.ResizeMode = ResizeMode.NoResize;
this.Left = 0;
this.Top = 0;
this.Width = SystemParameters.VirtualScreenWidth;
this.Height = SystemParameters.VirtualScreenHeight;
//this.Topmost = true;
_isFullScreen = true;
_originalScale = _mediaPlayer.Scale; // save original
_originalAspectRatio = _mediaPlayer.AspectRatio;
playerBar.Visibility = Visibility.Collapsed;
MediaTrack? mediaTrack;
try
{
mediaTrack = _mediaPlayer.Media?.Tracks?.FirstOrDefault(x => x.TrackType == TrackType.Video);
}
catch (Exception)
{
mediaTrack = null;
}
if (mediaTrack == null || !mediaTrack.HasValue)
{
return;
}
//get windows scale factor(DPI)
PresentationSource source = PresentationSource.FromVisual(this);
double dpiX=1.0, dpiY=1.0;
if (source != null)
{
dpiX = source.CompositionTarget.TransformToDevice.M11;
dpiY = source.CompositionTarget.TransformToDevice.M22;
}
var displayW = this.Width * dpiX;
var displayH = this.Height * dpiY;
var videoSwapped = mediaTrack.Value.Data.Video.Orientation == VideoOrientation.LeftBottom ||
mediaTrack.Value.Data.Video.Orientation == VideoOrientation.RightTop;
var videoW = mediaTrack.Value.Data.Video.Width;
var videoH = mediaTrack.Value.Data.Video.Height;
if (videoSwapped)
{
var swap = videoW;
videoW = videoH;
videoH = swap;
}
if (mediaTrack.Value.Data.Video.SarNum != mediaTrack.Value.Data.Video.SarDen)
videoW = videoW * mediaTrack.Value.Data.Video.SarNum / mediaTrack.Value.Data.Video.SarDen;
var ar = videoW / (float)videoH;
var dar = displayW / (float)displayH;
float scale;
if (dar >= ar)
scale = (float)displayW / videoW; /* horizontal */
else
scale = (float)displayH / videoH; /* vertical */
//keep ratio of width/height, not fill the srceen
//_mediaPlayer.Scale = scale; // 这是保持视频宽高比的,视频不会变形
//_mediaPlayer.AspectRatio = string.Empty;//这是保持视频宽高比的,视频不会变形
//这是视频变形适配屏幕的情况(满屏)
//fill all the screen by video,video is streched
float xscale, yscale;
xscale = (float)(displayW / videoW);
yscale = (float)(displayH / videoH);
_mediaPlayer.Scale = (xscale<yscale)? xscale:yscale;
string aspectRatio = String.Format("{0}:{1}",
this.Width,this.Height);
_mediaPlayer.AspectRatio = aspectRatio;
}
}

Can't navigation between xaml in frame?

I have got issues . Why did not it navigate to other xaml? Where is wrong?
So, I was trying to make it that can navigated between two or more xaml in a frame.
Here is link : https://github.com/Englbach/MutiViewInRootPage
<SplitView.Content>
<!-- OnNavigatingToPage we synchronize the selected item in the nav menu with the current page.
OnNavigatedToPage we move keyboard focus to the first item on the page after it's loaded. -->
<Frame x:Name="AppShellFrame">
<Frame.ContentTransitions>
<TransitionCollection>
<NavigationThemeTransition>
<NavigationThemeTransition.DefaultNavigationTransitionInfo>
<EntranceNavigationTransitionInfo />
</NavigationThemeTransition.DefaultNavigationTransitionInfo>
</NavigationThemeTransition>
</TransitionCollection>
</Frame.ContentTransitions>
</Frame>
</SplitView.Content>
public static AppShell Current = null;
public List<NavMenuItem> NavList { get; } = new List<NavMenuItem>(new[]
{
new NavMenuItem()
{
Symbol = Symbol.Add,
Label = "Add feed",
DestPage = typeof(RootPages),
Arguments = typeof(AddFeedView)
},
new NavMenuItem()
{
Symbol = Symbol.Edit,
Label = "Edit feeds",
DestPage = typeof(RootPages),
Arguments = typeof(EditFeedView)
}
});
public AppShell()
{
this.InitializeComponent();
Current = this;
}
private void NavMenuList_ItemInvoked(object sender, ListViewItem e)
{
NavMenuList.SelectedIndex = -1;
var item = (NavMenuItem)((NavMenuListView)sender).ItemFromContainer(e);
if(item!=null)
{
AppFrame.Navigate(typeof(RootPages), item.Arguments);
}
}
You probably followed the official Navigation menu (XAML) sample to design your layout.
There are two tiny problems in your demo.
Each time the items in the NavMenuList is clicked, the NavMenuList_ItemInvoked event in the AppShell.xaml.cs should be triggered. And in this event, you navigated again and again to your RootPages, and together pass the navigation parameter(item.Arguments) to the RootPages like this AppFrame.Navigate(typeof(RootPages), item.Arguments);, and the argument is actually your destination.
You can modify the code here like this:
private void NavMenuList_ItemInvoked(object sender, ListViewItem e)
{
//NavMenuList.SelectedIndex = -1;
var item = (NavMenuItem)((NavMenuListView)sender).ItemFromContainer(e);
if (item != null)
{
//AppFrame.Navigate(typeof(RootPages), item.Arguments);
if (item.DestPage != null &&
item.DestPage != this.AppFrame.CurrentSourcePageType)
{
this.AppFrame.Navigate(item.DestPage, item.Arguments);
}
}
}
Then here comes the second problem, as I said, the Arguments should be navigation parameter, for example, I navigate to AddFeedView page and I want to send a message "balalala", then we can code like this: AppFrame.Navigate(typeof(AddFeedView), "balalala");. This means, you confused with your DestPage and Arguments.
You can modify your NavList like this:
public List<NavMenuItem> NavList { get; } = new List<NavMenuItem>(new[]
{
new NavMenuItem()
{
Symbol = Symbol.Add,
Label = "Add feed",
DestPage = typeof(AddFeedView),
Arguments = typeof(RootPages)
},
new NavMenuItem()
{
Symbol = Symbol.Edit,
Label = "Edit feeds",
DestPage = typeof(EditFeedView),
Arguments = typeof(RootPages)
}
});
In additional, if you want your AppFrame to navigate to the RootPages at first by default, you can code like this:
public AppShell()
{
this.InitializeComponent();
Current = this;
AppFrame.Navigate(typeof(RootPages));
}

ToggleButton is always true MVVM WPF

I have a little problem. I have 3 states for a togglebutton - two checked and one unchecked, but it is always checked. I don't know why.
XAML:
<ToggleButton Grid.Row="0" Grid.Column="1" Style="{DynamicResource MetroCircleToggleButtonStyle}" IsChecked="{Binding Path=RepeatChecked}" Command="{Binding Path=RepeatCommand}">
<Image Source="../Ressources/repeat.png"></Image>
</ToggleButton>
C#:
private void RepeatFunction()
{
if (!this.RepeatChecked)
{
Console.WriteLine("Not checked");
this.RepeatChecked = true;
this.stateRepeat = StateRepeat.ONE;
}
else if (this.RepeatChecked && this.stateRepeat == StateRepeat.ONE)
{
Console.WriteLine("Not checked - 2");
this.RepeatChecked = true;
this.stateRepeat = StateRepeat.ALL;
}
else if (this.RepeatChecked)
{
Console.WriteLine("Checked");
this.RepeatChecked = false;
this.stateRepeat = StateRepeat.NONE;
}
}
The console write is always Checked. I really don't understand.
EDIT:
this.stateRepeat = StateRepear.NONE;
this.RepeatCommand = new CommandProvider(obj => RepeatFunction());
The problem is that on click of toggle button, you always set the RepeatChecked to false/true which is bind to IsChecked which updates toggle state sets unchecked/checked again; so checked changes to unchecked and unchecked changes to check. Comment the line in all three conditions and run the flow and you will see all conditions working.
private void RepeatFunction()
{
if (!this.RepeatChecked)
{
Console.WriteLine("Not checked");
////this.RepeatChecked = true;
this.stateRepeat = StateRepeat.ONE;
}
else if (this.RepeatChecked && this.stateRepeat == StateRepeat.ONE)
{
Console.WriteLine("Not checked - 2");
////this.RepeatChecked = true;
this.stateRepeat = StateRepeat.ALL;
}
else if (this.RepeatChecked)
{
Console.WriteLine("Checked");
////this.RepeatChecked = false;
this.stateRepeat = StateRepeat.NONE;
}
}

Windows phone LonglistSelector not rendering all items

I'm struggling with a longlistselector and item realized event. The problem I'm facing is that the longlistselector does not show all elements.
The code I'm doing is not using MVVM (I know that I should use, but in this scenario I can't...it was heritage code).
This is what I have:
XAML:
<Scrollviewer>
<stackpanel>
<phone:LongListSelector Margin="0,15,0,0" ScrollViewer.VerticalScrollBarVisibility="Visible" x:Name="LBhistory" LayoutMode="List"
BorderThickness="0,15,0,0" >
<phone:LongListSelector Margin="0,15,0,0" ScrollViewer.VerticalScrollBarVisibility="Visible" x:Name="LBDevices" LayoutMode="List" BorderThickness="0,15,0,0" >
<phone:LongListSelector Margin="0,15,0,0" ScrollViewer.VerticalScrollBarVisibility="Visible" x:Name="LBfiles" LayoutMode="List" BorderThickness="0,15,0,0" >
</stackpanel>
</ScrollViewer>
CS file:
private bool _isLoadingAllFile;
private int _pageNumber = 0;
private ObservableCollection<PhotoObject> allFiles = new ObservableCollection<PhotoObject>();
public BackupPivotPage()
{
....
this.Loaded += PivotPage_Loaded;
}
private void PivotPage_Loaded(object sender, RoutedEventArgs e)
{
LBfiles.ItemsSource = allFiles;
LBfiles.ItemRealized += LBfiles_ItemRealized;
searchImages(_pageNumber++);
}
private void searchImages(int p)
{
_isLoadingAllFile = true;
var x = dbAllFiles.Skip(p * GlobalSettings.PageSize.myPictures)
.Take(GlobalSettings.PageSize.myPictures);
foreach (var toAddObject in x)
{
this.allFiles.Add(toAddObject);
}
_isLoadingAllFile = false;
}
void LBfiles_ItemRealized(object sender, ItemRealizationEventArgs e)
{
try
{
if (!_isLoadingAllFile && LBfiles.ItemsSource != null &&
LBfiles.ItemsSource.Count >= Constants.offsetKnob)
{
if (e.ItemKind == LongListSelectorItemKind.Item)
{
if ((e.Container.Content as PhotoObject)
.Equals(LBfiles.ItemsSource[LBfiles.ItemsSource.Count - Constants.offsetKnob]))
{
searchImages(this._pageNumber++);
}
}
}
}
catch (Exception e1)
{
}
}
Right now my problem is that I know that allFiles has 96 elements, but only 67 are shown and the rest appear as white...any idea why?
EDIT
I've update with the scrollviewer...because I've 3 longlistselectors in the same page...and only this last one doesn't show all the items.
The problem seems to be around the time with which the data is loaded (or the thread). The ItemRealised event happens on a Background Thread therefore isn't able to update the User interface. In the example reference below they perform a similar operation to yours but retrieve the data using Deployment.Current.Dispatcher. This is used to do the work on the UI thread.
Try something similar to the following:
Try
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
var x = dbAllFiles.Skip(p * GlobalSettings.PageSize.myPictures)
.Take(GlobalSettings.PageSize.myPictures);
foreach (var toAddObject in x)
{
this.allFiles.Add(toAddObject);
}
IsLoading = false;
});
}
catch (Exception e)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show("Network error occured " + e.Message);
});
}
TwitterSearch - Windows Phone 8 LongListSelector Infinite Scrolling Sample

Categories