UWP - Swipe on ListView

1

I'm trying to develop an UWP application which will be running on a Raspberry PI with a 7" display. In the app I have a list of demands that I will update from a SQL Server database. The user needs to swipe and confirm the demands and change their status in the database and delete them from the list. The list will be refreshed on a timer.

The problem I'm having is when I try to identify which item the user swiped(and confirmed).

I'm new to UWP and I tried using the examples found on Microsoft Docs regarding this subject.

XAML code:

<Page.Resources>
    <SwipeItems x:Key="RevealOptions" Mode="Reveal">
        <SwipeItem Text="Confirm" Invoked="Confirm_Invoked">
            <SwipeItem.IconSource>
                <SymbolIconSource Symbol="Accept"/>
            </SwipeItem.IconSource>
        </SwipeItem>
    </SwipeItems>
</Page.Resources>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView x:Name="sampleList" Width="700" ItemsSource="{x:Bind inregistrari}">
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            </Style>
        </ListView.ItemContainerStyle>
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="local:inregistrare">
                <SwipeControl x:Name="ListViewSwipeContainer"
                      LeftItems="{StaticResource RevealOptions}"
                      Height="50">
                    <StackPanel Orientation="Vertical" Margin="5">
                        <Border Height="50" Width="690" BorderBrush="Blue" BorderThickness="2">
                            <TextBlock Text="{x:Bind info}" FontSize="20"/>
                        </Border>
                    </StackPanel>
                </SwipeControl>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>   
</Grid>

C# Code:

namespace Notificare_Driver
{

/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
/// 

public class inregistrare
{

    private long id { set; get; }
    private string workcenter { get; set; }
    private DateTime dateTime { get; set; }


    public inregistrare(long id, string workcenter, DateTime dateTime)
    {
        this.id = id;
        this.workcenter = workcenter;
        this.dateTime = dateTime;
    }

    public string info { get { return this.workcenter + " - " + this.dateTime.ToString(); } }


}

public sealed partial class MainPage : Page
{

    public ObservableCollection<inregistrare> inregistrari = new ObservableCollection<inregistrare>();

    public MainPage()
    {
        this.InitializeComponent();
        update_list();
    }

    private void update_list()
    {
        inregistrari.Clear();
        using (SqlConnection conn = new SqlConnection(connstr))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand("SELECT * FROM db WHERE status=0 ORDER by 'datetime' desc;", conn))
            {
                using (SqlDataReader rdr = cmd.ExecuteReader())
                {
                    while (rdr.Read())
                    {
                        long id = rdr.GetInt32(0);
                        string workcenter = rdr.GetString(1);
                        DateTime dateTime = rdr.GetDateTime(2);

                        inregistrari.Add(new inregistrare(id, workcenter, dateTime));
                    }
                }
            }
            conn.Close();
        }
    }

    private void Confirm_Invoked(SwipeItem sender, SwipeItemInvokedEventArgs args)
    {
        sampleList.Items.Remove(args.SwipeControl.DataContext);
    }
}

When I try to access args.SwipeControl.Data context the application crashes with the error:

System.Exception: 'Catastrophic failure
(Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))'.

Sorry if I'm missing something very obvious.

EDIT:

Made some progress with a workaround. I declared a method inside inregistrare where I update it's status in the database, so every instance will do that for itself.

public void update_status()
    {
        using (SqlConnection conn = new SqlConnection(connstr))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand("UPDATE db SET status = 1 WHERE id="+this.id+";", conn))
            {
                cmd.ExecuteNonQuery();
            }
            conn.Close();
        }
    }

In my handler for the swipe confirm I do this now:

private void Confirm_Invoked(SwipeItem sender, SwipeItemInvokedEventArgs args)
    {
        try { 
            inregistrare temp = (inregistrare)args.SwipeControl.DataContext;
            temp.update_status(); // this line throws the exception, but only after the method call is over
        }
        catch(Exception ex)
        {
            mesaj.Text = ex.Message.ToString();
        }

        try 
        {
            update_list();
        }
        catch(Exception ex)
        {
            mesaj2.Text = ex.Message.ToString();
        }
    }

mesaj and mesaj2 are just some text boxes used for debugging. This workaround works(it's kinda slow, as for every swiped item it loses time in the try block), even tho after it updates it's status in the database throws an "Object reference not set" error(it appears in mesaj textbox; mesaj2 remains empty).

c#
xaml
uwp
asked on Stack Overflow Mar 27, 2018 by Loga Alex • edited Mar 28, 2018 by Loga Alex

1 Answer

1

If your SwipeControls all have unique names, you can access their names in the SwipeItem's invoked event like so (C# example):

    //Swipe Invoked
    private void Invoked(SwipeItem sender, SwipeItemInvokedEventArgs args)
    {
        //Get name of SwipeControl
        string name = args.SwipeControl.Name.ToString();

        //More code here

    }
answered on Stack Overflow Mar 21, 2019 by scoots

User contributions licensed under CC BY-SA 3.0