Removing an item from a list in Xamarin forms - xaml

The issue i'm having is when I delete a row from my list in Xamarin forms, I have it set up so when the user wants to delete something, they will get a pop up asking if they really want to delete. If they push yes it removes the item from the list..(not a problem) but if the user says no it still removes the item (temperately) you then refresh the page and it will come back. I am wondering what I have wrong in my code. so it doesn't remove the item unless you push yes..
async void OnDeleteBook(object sender, EventArgs e)
{
var book = (sender as MenuItem).CommandParameter as BooksIWant;
if (await DisplayAlert("Warning", $"Are you sure you want to delete {book.Author} {book.BookTitle}?", "Yes", "No"))
await _connection.DeleteAsync(book);
_booksIWant.Remove(book);
}

You need to use {} to create a block of statements. Without them, only the statement immediately after the IF is executed;
if (await DisplayAlert("Warning", $"Are you sure you want to delete {book.Author} {book.BookTitle}?", "Yes", "No"))
{
await _connection.DeleteAsync(book);
_booksIWant.Remove(book);
}
This is basic C#, not anything specific to Xamarin.

You should code like below
async void OnDeleteBook(object sender, EventArgs e){
var book = (sender as MenuItem).CommandParameter as BooksIWant;
if (await DisplayAlert("Warning", $"Are you sure you want to delete {book.Author} {book.BookTitle}?", "Yes", "No")){
await _connection.DeleteAsync(book);
_booksIWant.Remove(book);}}
Delete and Remove method call needs to be inside the if loop

Related

how to take property value using droptarget?

I am creating a plugin and i need to know the value of porosity of reservoir. If these properties exist somewhere it would be much easier if I could just access them.
So how can we take these value using "drop target button" ?
You must subscribe to the DropTarget.DragDrop event. The following callback method shows you how to get the object dropped on the DropTarget button.
void DropTarget_DragDrop(object sender, DragEventArgs e)
{
Property property = e.Data.GetData(typeof(object)) as Property;
if (property == null)
return;
// Do something with property, like show it in a
// PresentationBox or store it for use later.
}

Number of Touchpoints in GestureRecognizer

I am using the GestureRecognizer to detect drag and pinch gestures.
The ManipulationStarted, ManipulationUpdated and ManipulationCompleted events provide the translation and scale values that are needed to pinch and drag.
However I cant figure out how to distinguish between drag (1 touch point) and pinch (2 touch points) gestures. There is no information about the number of touchpoints in GestureRecognizer.
How can I distinguish between drag and pinch with the GestureRecognizer?
Well, I feel it is very hacky (as most solutions seem to be for a useable WinRT app) but you can create a List<uint> to keep track of the number of pointers that are currently down on the screen. You would have to handle the PointerPressed event on whatever control you are interacting with (Let's say you are using a Canvas) to "capture" the pointers as they are pressed. That is where you would populate the List<uint>. Don't forget to clear the list at the end of the ManipulationCompleted event as well as any event that would fire upon the end of any gestures (like PointerReleased, PointerCanceled, and PointerCaptureLost). Maybe it would be a good idea to make sure the list is cleared in the ManipulationStarted event. Perhaps you can try that and see how that works for you.
In the ManipulationCompleted event, you can check if your List contains exactly 2 elements (PointerIds). If so, then you know it is a pinch/zoom.
Here is what it could look like:
private void Canvas_PointerPressed(object sender, PointerRoutedEventArgs e)
{
var ps = e.GetIntermediatePoints(null);
if (ps != null && ps.Count > 0)
{
this.gestureRecognizer.ProcessDownEvent(ps[0]);
this.pointerList.Add(e.Pointer.PointerId);
e.Handled = true;
}
}
private void gestureRecognizer_ManipulationCompleted(GestureRecognizer sender, ManipulationCompletedEventArgs args)
{
if (this.pointerList.Count == 2)
{
// This could be your pinch or zoom.
}
else
{
// This could be your drag.
}
// Don't forget to clear the list.
this.pointerList.Clear();
}
// Make sure you clear your list in whatever events make sense.
private void Canvas_PointerReleased(object sender, PointerRoutedEventArgs e)
{
this.pointerList.Clear();
}
private void Canvas_PointerCanceled(object sender, PointerRoutedEventArgs e)
{
this.pointerList.Clear();
}
I have been struggling with the same question for a few hours now and it looks WinRT platform does not provide that. What it instead provides is Delta.Rotation and Delta.Scale values in addition to Delta.Translation with the arguments to ManipulationUpdated callback.
If Delta.Rotation is 0 (or very close to zero - because it is a float value) and Delta.Scale is 1 (or very close to 1), you can conclude that a pinch operation is not the case and a drag operation is being carried otherwise it is a pinch operation. It is not the best you can get but it looks it is the only availability for the time being.

Unsubscribe from IObservableElementEnumerable.EnumerableChanged doesn't work?

Parts of our UI uses IObservableElementEnumerable.EnumerableChanged in order to update if the user e.g. deletes a domain object from a folder.
When the UI is disposed, we unsubscribe from the event... or so we thought. It turns out that the unsubscribe doesn't have any effect, and our event handler is still called. This caused a number of odd bugs, but also leads to memory leaks.
The only time unsubscription works, is if we store the IObservableElementEnumerable reference instead of calling IObservableElementEnumerableFactory.GetEnumerable(obj) again. But this, in turn, is likely to keep a live reference to the folder object, which will break if the folder itself is deleted by the user.
This is particularly puzzling as the GetEnumerable() documentation clearly states: "It is expected that subsequent calls with the same domain object will yield the same instance of IObservableElementEnumerable." Is this not to be interpreted as a guarantee?
Should there be any reason for unsubscription not working?
The following code replicates the issue on Petrel 2011 (add to a simple plugin with a menu extension, or get the full solution here (DropBox)):
using System;
using System.Linq;
using System.Windows.Forms;
using Slb.Ocean.Core;
using Slb.Ocean.Petrel;
using Slb.Ocean.Petrel.Basics;
using Slb.Ocean.Petrel.UI;
namespace ObservableElementEnumerable
{
public class OEEForm : Form
{
private Droid _droid;
private bool _disposed;
public OEEForm()
{
IInput input = PetrelProject.Inputs;
IIdentifiable selected = input.GetSelected<object>().FirstOrDefault() as IIdentifiable;
if (selected == null)
{
PetrelLogger.InfoOutputWindow("Select a folder first");
return;
}
_droid = selected.Droid;
GetEnumerable().EnumerableChanged += enumerable_EnumerableChanged;
PetrelLogger.InfoOutputWindow("Enumerable subscribed");
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing && !_disposed)
{
GetEnumerable().EnumerableChanged -= enumerable_EnumerableChanged;
PetrelLogger.InfoOutputWindow("Enumerable unsubscribed (?)");
_droid = null;
_disposed = true;
}
}
IObservableElementEnumerable GetEnumerable()
{
if (_disposed)
throw new ObjectDisposedException("OEEForm");
object obj = DataManager.Resolve(_droid);
IObservableElementEnumerableFactory factory = CoreSystem.GetService<IObservableElementEnumerableFactory>(obj);
IObservableElementEnumerable enumerable = factory.GetEnumerable(obj);
return enumerable;
}
void enumerable_EnumerableChanged(object sender, ElementEnumerableChangeEventArgs e)
{
PetrelLogger.InfoOutputWindow("Enumerable changed");
if (_disposed)
PetrelLogger.InfoOutputWindow("... but I am disposed and unsubscribed!");
}
}
public static class Menu1
{
public static void OEEBegin1_ToolClick(object sender, System.EventArgs e)
{
OEEForm f = new OEEForm();
f.Show();
}
}
}
To replicate:
Run Petrel with the plugin
Load a project with a folder with objects
Select the folder
Activate the plugin menu item
With the popup open, delete an object in the folder
Close the Form popping up
Delete an object in the folder
The message log should clearly show that the event handler is still called after the form is disposed.
You already keep a reference to the underlying enumerable by connecting the event. Events are references as well. Just keep a reference to the enumerable and unsubscribe from the same instance as the one you subscribe to.
To deal with the issue of objects that are deleted by the user you need to listen to the delete event.

TextBox DataField always updating source bindings on text changed with text box that fails validation

I have a TextBox with a two-way binding on the input. It is setup such that it fails validation if it is empty and displays a tooltip saying that it cannot be empty. My problem is that because it is failing validation, it tries to update the bindings everytime the text box changes (i.e. with every key press). I do not want it to update the source with every key press. I've narrowed it down to this code in the Silverlight 4.0 Tool kit for DataField.cs:
private void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox != null && (ValidationUtil.ElementHasErrors(textBox) || !this._lostFocusFired[textBox]))
{
this._lostFocusFired[textBox] = false;
ValidationUtil.UpdateSourceOnElementBindings(textBox);
}
}
It is falling into the ValidationUtil.UpdateSourceOnElementBindings() because the element has errors. Is there anyway I can prevent it from doing this?
I think you want help rearranging your conditions to more accurately express your intent, but I'm not clear on what the existing code's result would be. This is why we ask for a complete, runnable (but minimal!) test case. However, if you simply don't want to update due to a failed validation, this should do the trick:
private void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox != null && !this._lostFocusFired[textBox]))
{
ValidationUtil.UpdateSourceOnElementBindings(textBox);
}
}
You can validate the input and react to the result outside of that if statement.

Silverlight 4 Asynchronous Issue

I am creating an application in Silverlight 4. The first screen the user comes in contact with is the Login screen (Login.xaml). I have written the following code in Login.xaml.cs file.
private void btnSubmit_Click(object sender, RoutedEventArgs e)
{
//first validate if the user is authorised for this application
if (this.ValidateEntry())
{
if (UserAuthenticationBL.AuthenticateUser(txtUserName.Text.Trim(), txtPassword.Password.Trim()))
{
//since the user is authenticated we will show the dashboard screen
this.Content = new MainPage();
}
else
{
this.ShowErrorMessage("Invalid username or password");
txtUserName.Focus();
}
}
}
My problem is that the code gets executed before i get the data in the AuthenticateUser method. The code immediately comes down to the "Invalid username or password" and the list is loaded after all the execution on the xaml page has finished.
I know there is something going wrong with the Asynchronous thingi...and i also know i need to put an event to know when the loading has completed........
but i dont know how to go about it!!!
can someone please put some light on this issue...
thank you.
If I understood it right, your AuthenticateUser method is running async, right?
You have to define a callback to the AuthenticateUserComplete event and run the method in the button submit event. In the callback write this if/else clause, then it will be called once the asynchronous method was completed.
Just one question, why are you doing asynchronously if your behavior should be synchronous? (You have to get the answer before deciding what to do).
This http://msdn.microsoft.com/en-us/library/aa719598%28VS.71%29.aspx
may be helpful :)
Oscar