1
votes

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).

1
Did you use breakpoint to see the values in args? - Vijay Nirmal
It's an object of type inregistrare(my defined class), so it's what it should be. - Loga Alex
Sadly, I don't have a touchscreen to check this. So I can only give my advice to debug it yourself. - Vijay Nirmal
At which line the exception occurs? - Vijay Nirmal
In Confirm_Invoked(), where I try to remove it from the list. I can't do anything with args.SwipeControl.DataContext, not even output it to a text box. When I try that I get this : System.NullReferenceException: 'Object reference not set to an instance of an object.' even if in the debugger I can see it's an object of type inregistrare and it has the members set to the value of what I swiped. - Loga Alex

1 Answers

1
votes

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

    }