OnElementPropertyChanged called infinely in xamarin forms - xamarin

I have a custom Time picker renderer in my xamarin forms application
In my renderer i have
protected override void OnElementPropertyChanged(object sender,
PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
try
{
if (e.PropertyName == iOSCustomTimePicker.TimeProperty.PropertyName)
{
var temp = sender as iOSCustomTimePicker;
picker.Hour = temp.Time.Hours;
picker.Minute = temp.Time.Minutes;
//TimeSpan value = new TimeSpan(8, 0, 0);
//this.Element.SetValue(iOSCustomTimePicker.TimeProperty, value);
}
}
catch (Exception e1)
{
}
}
And i use it in xaml
<control:iOSCustomTimePicker x:Name="cli_staffrequest_addShiftTime_timePicker1" Grid.Column="2" Grid.Row="1" Time="{Binding ShiftEndTimeSelected}"
HorizontalOptions="Fill" VerticalOptions="Fill" StyleId="uit_staffHiring_addShifts__timePicker1"/>
So when the ShiftEndTimeSelected in ViewModel changes i get a hit in OnElementPropertyChanged and i change the time
Now my issue is sometimes i get infinite hits in OnElementPropertyChanged
and thus calling the Garbage Collector infinitely. How to figure out whats wrong. I am completely new to xamarin Forms

Sorry for the poor english
I think those lines are raising the event again:
base.OnElementPropertyChanged(sender, e);
and
picker.Hour = temp.Time.Hours;
picker.Minute = temp.Time.Minutes;
Maybe this will not happens if you make this way on your event handler (you need to test):
try
{
if (e.PropertyName == iOSCustomTimePicker.TimeProperty.PropertyName)
{
var temp = sender as iOSCustomTimePicker;
picker.Hour = temp.Time.Hours;
picker.Minute = temp.Time.Minutes;
}
else
base.OnElementPropertyChanged(sender, e);
}
catch (Exception e1)
{
}

Related

Messeging center hits multiple times when sending from Shared code to platform code- Xamarin.forms

I know these questions asked several times on SO. But I can't able to solve this. In my xamarin.forms app, I am showing a camera inside one page using custom Camera View. The button for taking a picture is in a shared code. For taking a picture from shared code, I am using the Messaging Center. When we click the button the messaging center send from shared code will subscribe to my camera custom Render and picture taking action will happen.
The problem I am facing is the subscribing part of the Messaging center will hit multiple times. The weird thing is the subscribing will increase each time when we click the button. I added the Unsubscribe messaging center. Then it will no longer hit. What will be the cause of this problem? Any help is appreciated.
My shared code Portion where messaging center send.
private async void Capture_Tapped(object sender, EventArgs e)
{
try
{
MessagingCenter.Send<CameraPopup>(this, "CaptureClick");
}
catch (Exception)
{
}
}
Messeging center subscribing portion on android Camera Custom render
protected async override void OnElementChanged(ElementChangedEventArgs<Centraverse.Views.Clocking.CustomCamera.CameraPreview> e)
{
base.OnElementChanged(e);
if (Control == null)
{
cameraPreview = new CameraPreview(Context);
SetNativeControl(cameraPreview);
// This portion hitting multiple times
MessagingCenter.Subscribe<CameraPopup>(this,"CaptureClick", (sender) =>
{
try
{
Log.Info("Reached here:","Try catch of first ");
if (DetectedFaceCount == 0)
{
//Do Action
}
else if (DetectedFaceCount == 1)
{
Control.Preview.StopFaceDetection();
Task.Run(() => takepicture());
}
else if (DetectedFaceCount > 1)
{
//Do Action
}
}
catch (Exception ex)
{
return;
}
// MessagingCenter.Unsubscribe<CameraPopup>(this, "CaptureClick");
});
}
if (e.OldElement != null)
{
}
if (e.NewElement != null)
{
try
{
Control.Preview = Camera.Open((int)e.NewElement.Camera);
Device.BeginInvokeOnMainThread(async () =>
{
Control.Preview.SetFaceDetectionListener(this);
Control.Preview.StartFaceDetection();
});
}
catch (Exception ex)
{
return;
}
}
}
According to your description and to the code there can be just one reason for this - you are subscribing multiple times to the event. So you need to unsubscribe first or to have some internal tracking mechanism that you have subscribed and to do it just once.

Touch event cancels Tap Gesture Recognizer in xamarin

I am using SkiaSharp library to draw on canvas .
and I need to set a tap recognizer to a specific function when I double tap .
and the touch event of the canvas to do another functions .
each one works well separately but when I use them both , the Touch event cancels the Tap Recognizer .
is there is any way to use them both ?
<skia:SKCanvasView x:Name="canvasView"
PaintSurface="canvasView_paintSurface"
VerticalOptions="FillAndExpand"
EnableTouchEvents="true"
Touch="OnTouch">
<skia:SKCanvasView.GestureRecognizers >
<TapGestureRecognizer NumberOfTapsRequired="2" Tapped="OnTapped" >
</TapGestureRecognizer>
</skia:SKCanvasView.GestureRecognizers>
</skia:SKCanvasView>
private void OnTapped(object sender, EventArgs e)
{
DisplayAlert("hello", "OnTapped", "Ok", "Cancel");
}
private async void OnTouch(object sender, SKTouchEventArgs e)
{
DisplayAlert("hello", "OnTouch", "Ok", "Cancel");
}
One way of solving this is by creating two tap gesture recognizers and a timer to check the succession of the taps. This way you know whether there was a touch or a double tap
private bool tapHandled;
public XYZPage() : base()
{
var tgr = new TapGestureRecognizer();
tgr.NumberOfTapsRequired = 1;
tgr.Tapped += tapped;
GestureRecognizers.Add(tgr);
var ttgr = new TapGestureRecognizer();
ttgr.NumberOfTapsRequired = 2;
ttgr.Tapped += doubletapped;
GestureRecognizers.Add(ttgr);
}
private void tapped(object sender, EventArgs e)
{
tapHandled = false;
Xamarin.Forms.Device.StartTimer(new TimeSpan(0, 0, 0, 0, 300), taptimer);
}
private void doubletapped(object sender, EventArgs e)
{
tapHandled = true;
// do double tap work here
DisplayAlert("hello", "OnDoubleTapped", "Ok", "Cancel");
}
private bool taptimer()
{
if (!tapHandled)
{
tapHandled = true;
// do Touch stuff here
DisplayAlert("hello", "OnTouch", "Ok", "Cancel");
}
return false;
}

How to stop led torch/flashlight app using Reflection in Windows Phone 7

I am making an Flashlight app, in which I need to use the camera's LED constantly on pressing ON button and OFF it on pressing the same button. I followed this article Turning on the LED with the video camera using Reflection. The ON/OFF operation works fine only once. The Code is as:
private VideoCamera _videoCamera;
private VideoCameraVisualizer _videoCameraVisualizer;
bool _isFlashOff = true;
private void FlashButton_Click(object sender, RoutedEventArgs e)
{
try
{
if (_isFlashOff)
{
_isFlashOff = false;
// Check to see if the camera is available on the device.
if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary))
{
// Use standard camera on back of device.
_videoCamera = new VideoCamera();
// Event is fired when the video camera object has been initialized.
_videoCamera.Initialized += VideoCamera_Initialized;
// Add the photo camera to the video source
_videoCameraVisualizer = new VideoCameraVisualizer();
_videoCameraVisualizer.SetSource(_videoCamera);
}
}
else
{
_isFlashOff = true;
_videoCamera.StopRecording();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void VideoCamera_Initialized(object sender, EventArgs e)
{
_videoCamera.LampEnabled = true;
_videoCamera.StartRecording();
}
Since there was no implementation of StopRecording Method in VideoCamera class as specified in the article: Turning on the LED with the video camera using Reflection . I made the function as:
public void StopRecording()
{
// Invoke the stop recording method on the video camera object.
_videoCameraStopRecordingMethod.Invoke(_videoCamera, null);
}
The problem is when I again press ON button "Exception' is thrown as "TargetInvocationException". I am unable to figure out the problem that causes exception. Is StopRecording() function right..??
That's because you should initialize the camera only once. Do it during the OnNavigatedTo event, then re-use the same instances:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
// Use standard camera on back of device.
_videoCamera = new VideoCamera();
// Event is fired when the video camera object has been initialized.
_videoCamera.Initialized += VideoCamera_Initialized;
// Add the photo camera to the video source
_videoCameraVisualizer = new VideoCameraVisualizer();
_videoCameraVisualizer.SetSource(_videoCamera);
}
private void VideoCamera_Initialized(object sender, EventArgs e)
{
isInitialized = true;
}
bool isInitialized;
bool isFlashEnabled;
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (!isInitialized)
{
MessageBox.Show("Please wait during camera initialization");
return;
}
if (!isFlashEnabled)
{
isFlashEnabled = true;
// Check to see if the camera is available on the device.
if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary))
{
_videoCamera.LampEnabled = true;
_videoCamera.StartRecording();
}
}
else
{
isFlashEnabled = false;
_videoCamera.StopRecording();
}
}
Try this:
http://msdn.microsoft.com/en-us/library/hh202949.aspx

ListBox and selectedIndexChanged event after the user hit the back button

In my windows phone 7 app, I have the following code to handle the OnSelectedIndexChange of a ListBox.
private void wordList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
WordList selectedList = (WordList)e.AddedItems[0];
NavigationService.Navigate(new Uri("/Views/Game.xaml?ListName=" + selectedList.Name, UriKind.RelativeOrAbsolute));
}
The above code work fine, However if the user click on the hardware back button from the Game page, and click on the same listbox item, the above code is not called. I assume this is because the selected item is the same therefore the SelectionChanged event is not being called.
How do I make it so that if the user select the same item I can still send them to the Game page?
I looked at the Tap Event but I couldn't figure out a way to get the selected Item from the tab event.
When using SelectionChanged to navigate, surround your navigation logic with a check to see if the SelectedIndex = -1. After you navigate, set the index to -1, so that the event will not fire twice.
private void wordList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var lb = sender as ListBox;
if (lb != null)
{
if (lb.SelectedIndex == -1) return;
WordList selectedList = (WordList)e.AddedItems[0];
NavigationService.Navigate(new Uri("/Views/Game.xaml?ListName=" + selectedList.Name, UriKind.RelativeOrAbsolute));
lb.SelectedIndex = -1;
}
}
This way you can get the selected Item from the Tap event.
private void wordList_Tap(object sender, GestureEventArgs e)
{
var selectedElement = e.OriginalSource as FrameworkElement;
if (selectedElement != null)
{
var selectedData = selectedElement.DataContext as WordList;
if (selectedData != null)
{
NavigationService.Navigate(new Uri("/Views/Game.xaml?ListName=" + selectedData.Name, UriKind.RelativeOrAbsolute));
}
}
}
I had such issue within a UserControl. Check the sender, and return if it is not the ListBox control which is triggering the event:
protected void cbEvents_SelectedIndexChanged(object sender, EventArgs e)
{
if (sender is DropDownList)
RebindGrid();
}

windows phone 7 ListBox event confusion

The app is like a small dictionary. I have a listbox and a textbox. The list box is already filled with words and when there is any entry in the textbox the listbox is refilled again with words starting with the letters in the textbox. I have a listbox SelectionChanged event implemented when the user clicks on a word its meaning appears. The problem is when user selects a word from the list and then types something in the textbox, listBox SelectionChanged event is called i dont want this to happen because at this point of time my listbox's selected item is empty.I would like to have a event that is fired only when user selects something from the listbox. It should not be fired when the content of the listbox changes. Thank you
You can use
1.if (lstWords.SelectedItem != null)
2.lstWords.SelectedIndex = -1;
for e.g. following is the source code for text changed event and list selection change event
private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
try
{
if (textBox1.Text.ToString().Equals(""))
{
XmlDictionaryRepository test = new XmlDictionaryRepository();
lstWords.ItemsSource = test.GetWordList(categorySelected,xmlFileName);
}
else
{
XmlDictionaryRepository test = new XmlDictionaryRepository();
lstWords.ItemsSource = test.GetMatchWordList(categorySelected, textBox1.Text.ToString(),xmlFileName);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString(), (((PhoneApplicationFrame)Application.Current.RootVisual).Content).ToString(), MessageBoxButton.OK);
}
}
private void lstWords_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
if (lstWords.SelectedItem != null)
{
string wordSelected = ((Glossy_Test.Dictionary)(lstWords.SelectedItem)).Word;
if (lstWords.SelectedItem != null)
{
NavigationService.Navigate(new Uri(string.Format("/DescribeWord.xaml?param1={0}&param2={1}", wordSelected, categorySelected), UriKind.Relative));
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString(), (((PhoneApplicationFrame)Application.Current.RootVisual).Content).ToString(), MessageBoxButton.OK);
}
finally
{
// lstWords.SelectedIndex = -1;
}
}

Resources