private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            #region ADDED TO SAMPLE TO DEMONSTRATE Portable.Data.Sqlite
            try {
                string myTableName = "TestTable1";
                string sql;

                //Get a handle to App and instantiate my "crypt engine"
                var myApp = (App)Application.Current;
                myApp.AppCryptEngine = myApp.AppCryptEngine ?? new FakeCryptEngine(myApp.AppPassword);

                #region Part 1 - ADO - Create a table, add a record, add a column, add encrypted data, read back data

                using (var dbConn = new SqliteAdoConnection(myApp.SqliteConnection, myApp.AppCryptEngine)) {
                    Console.WriteLine("PART 1 - Doing ADO stuff");

                    //Create the table if it doesn't exist
                    sql = "CREATE TABLE IF NOT EXISTS " + myTableName + " (IdColumn INTEGER PRIMARY KEY AUTOINCREMENT, DateTimeColumn DATETIME, TextColumn TEXT);";
                    using (var cmd = new SqliteCommand(sql, dbConn)) {
                        dbConn.SafeOpen();
                        cmd.ExecuteNonQuery();
                        Console.WriteLine("Table [" + myTableName + "] created (if it didn't exist).");
                    }

                    //Add a record
                    sql = "INSERT INTO " + myTableName + " (DateTimeColumn, TextColumn) VALUES (@date, @text);";
                    int newRowId;
                    using (var cmd = new SqliteCommand(sql, dbConn)) {
                        cmd.Parameters.Add(new SqliteParameter("@date", DateTime.Now));
                        cmd.Parameters.Add(new SqliteParameter("@text", "Hello SQLite."));
                        dbConn.SafeOpen();
                        newRowId = Convert.ToInt32(cmd.ExecuteReturnRowId());  //Note: INTEGER columns in SQLite are always long/Int64 - including ID columns, so converting to int
                        Console.WriteLine("A record with ID " + newRowId.ToString() + " was created in table [" + myTableName + "].");
                    }

                    //Read the datetime column on the oldest record
                    sql = "SELECT [DateTimeColumn] FROM " + myTableName + " ORDER BY [DateTimeColumn] LIMIT 1;";
                    using (var cmd = new SqliteCommand(sql, dbConn)) {
                        dbConn.SafeOpen();
                        DateTime oldest = Convert.ToDateTime(cmd.ExecuteScalar());
                        Console.WriteLine("The oldest record in table [" + myTableName + "] has timestamp: " + oldest.ToString());
                    }

                    //Add an encrypted column to the table
                    //NOTE: There is no benefit to creating the column as SQLite datatype ENCRYPTED vs. TEXT
                    //  It is actually a TEXT column - but I think it is nice to set it to type ENCRYPTED for future purposes.
                    //  Hopefully a future version of SQLitePCL will make it easy to figure out if a column is defined as ENCRYPTED or TEXT
                    //  (right now, it identifies both as TEXT)
                    sql = "ALTER TABLE " + myTableName + " ADD COLUMN EncryptedColumn ENCRYPTED;";
                    //Note: This column shouldn't exist until the above sql is run, since I just created the table above.  But if this application has been run multiple times,
                    //  the column may already exist in the table - so I need to check for it.
                    bool columnAlreadyExists = false;
                    #region Check for column
                    using (var checkCmd = new SqliteCommand(dbConn)) {
                        checkCmd.CommandText = "PRAGMA table_info (" + myTableName + ");";
                        dbConn.SafeOpen();
                        using (var checkDr = new SqliteDataReader(checkCmd)) {
                            while (checkDr.Read())
                            {
                                if (checkDr.GetString("NAME") == "EncryptedColumn")
                                {
                                    Console.WriteLine("The [EncryptedColumn] column already exists.");
                                    columnAlreadyExists = true;
                                    break;
                                }
                            }
                        }
                    }
                    #endregion
                    if (!columnAlreadyExists)
                    {
                        using (var cmd = new SqliteCommand(sql, dbConn)) {
                            dbConn.SafeOpen();
                            cmd.ExecuteNonQuery();
                            Console.WriteLine("The [EncryptedColumn] column was created in table [" + myTableName + "].");
                        }
                    }

                    //Add a record with an encrypted column value
                    sql = "INSERT INTO " + myTableName + " (DateTimeColumn, TextColumn, EncryptedColumn) VALUES (@date, @text, @encrypted);";
                    using (var cmd = new SqliteCommand(sql, dbConn)) {
                        cmd.Parameters.Add(new SqliteParameter("@date", DateTime.Now));
                        cmd.Parameters.Add(new SqliteParameter("@text", "Hello data."));
                        cmd.AddEncryptedParameter(new SqliteParameter("@encrypted",
                                                                      Tuple.Create <string, string, string>("Hello", "encrypted", "data")));
                        dbConn.SafeOpen();
                        newRowId = Convert.ToInt32(cmd.ExecuteReturnRowId());  //Note: INTEGER columns in SQLite are always long/Int64 - including ID columns, so converting to int
                        Console.WriteLine("A record featuring encrypted data with ID " + newRowId.ToString() + " was created in table [" + myTableName + "].");
                    }

                    //Get the value of the encrypted column
                    sql = "SELECT [EncryptedColumn] FROM " + myTableName + " WHERE [IdColumn] = @id;";
                    using (var cmd = new SqliteCommand(sql, dbConn)) {
                        cmd.Parameters.Add(new SqliteParameter("@id", newRowId));
                        dbConn.SafeOpen();
                        string encryptedColumnValue = cmd.ExecuteScalar().ToString();
                        var    decryptedValue       = myApp.AppCryptEngine.DecryptObject <Tuple <string, string, string> >(encryptedColumnValue);
                        Console.WriteLine("The actual (encrypted) value of the [EncryptedColumn] column of record ID " + newRowId.ToString() + " is: " + encryptedColumnValue);
                        Console.WriteLine("The decrypted value of the [EncryptedColumn] column of record ID " + newRowId.ToString() + " is: " +
                                          decryptedValue.Item1 + " " + decryptedValue.Item2 + " " + decryptedValue.Item3);
                    }

                    //Using a SqliteDataReader and GetDecrypted<T> to get all of the encrypted values
                    sql = "SELECT [IdColumn], [DateTimeColumn], [EncryptedColumn] FROM " + myTableName + ";";
                    using (var cmd = new SqliteCommand(sql, dbConn)) {
                        dbConn.SafeOpen();
                        using (var dr = new SqliteDataReader(cmd)) {
                            while (dr.Read())
                            {
                                var sb = new StringBuilder();
                                sb.Append("ID: " + dr.GetInt32("IdColumn").ToString());
                                sb.Append(" - Timestamp: " + dr.GetDateTime("DateTimeColumn").ToString());
                                //IMPORTANT: By default, GetDecrypted<T> will throw an exception on a NULL column value.  You can specify DbNullHandling.ReturnTypeDefaultValue
                                // to return the default value of the specified type - as in default(T) - when a NULL column value is encountered, if you choose.
                                var decryptedValue = dr.GetDecrypted <Tuple <string, string, string> >("EncryptedColumn", DbNullHandling.ReturnTypeDefaultValue);
                                sb.Append(" - Value: " + ((decryptedValue == null) ? "NULL" :
                                                          decryptedValue.Item1 + " " + decryptedValue.Item2 + " " + decryptedValue.Item3));
                                Console.WriteLine(sb.ToString());
                            }
                        }
                    }
                }

                #endregion

                #region Part 2 - EncryptedTable - Create an encrypted table to hold SampleDataItem objects, and read and write data

                long numRecords;

                using (var dbConn = new SqliteAdoConnection(myApp.SqliteConnection, myApp.AppCryptEngine)) {
                    Console.WriteLine(" ");
                    Console.WriteLine("PART 2 - Doing EncryptedTable stuff");

                    //Creating the encrypted table, adding some items/records
                    using (var encTable = new EncryptedTable <SampleDataItem>(myApp.AppCryptEngine, dbConn)) {
                        //Shouldn't need to call CheckDbTable manually, but I am going to check to see if there are
                        //  records in the table, so I need to make sure the table exists
                        //This will check the table and create the table and/or any missing columns if needed.
                        encTable.CheckDbTable();

                        //Check to see how many records are in the table now
                        numRecords = SampleDataItem.GetNumRecords(dbConn, encTable.TableName);
                        Console.WriteLine("(1) There are currently " + numRecords.ToString() + " records in the table: " + encTable.TableName);

                        foreach (var item in ExampleData.GetData().Where(i => i.LastName != "Johnson"))
                        {
                            encTable.AddItem(item);
                        }

                        Console.WriteLine("(2) There are currently {0} items to be written to the encrypted table: {1}",
                                          encTable.TempItems.Where(i => i.IsDirty).Count(), encTable.TableName);

                        //Note that at this point in the code, nothing new has been written to the table yet.
                        //  The table will be updated on encTable.Dispose (in this case, that happens automatically at the end of this using() code
                        //  block) or we could force it now with encTable.WriteItemChanges()

                        //encTable.WriteItemChanges();
                    }

                    //Adding a couple more records...
                    using (var encTable = new EncryptedTable <SampleDataItem>(myApp.AppCryptEngine, dbConn)) {
                        //Because encTable was disposed above, we should now see records in the table
                        numRecords = SampleDataItem.GetNumRecords(dbConn, encTable.TableName);
                        Console.WriteLine("(3) There are currently " + numRecords.ToString() + " records in the table: " + encTable.TableName);

                        //Here is one way to add an item to the table - immediately
                        //  (no need to type out 'immediateWriteToTable:' - but just wanted to show what the 'true' was for)
                        encTable.AddItem(ExampleData.GetData().Where(i => i.FirstName == "Bob").Single(), immediateWriteToTable: true);

                        //Another way to add items to the table - wait until WriteItemChanges() or WriteChangesAndFlush() or encTable.Dispose()
                        //  is called
                        encTable.AddItem(ExampleData.GetData().Where(i => i.FirstName == "Joan").Single(), immediateWriteToTable: false);
                        encTable.AddItem(ExampleData.GetData().Where(i => i.FirstName == "Ned").Single());

                        //Should only see one more record - Joan and Ned haven't been written yet
                        numRecords = SampleDataItem.GetNumRecords(dbConn, encTable.TableName);
                        Console.WriteLine("(4) There are currently " + numRecords.ToString() + " records in the table: " + encTable.TableName);

                        //Let's see which items we have in memory right now
                        foreach (var item in encTable.TempItems)
                        {
                            Console.WriteLine("In memory: ID#{0} {1} {2} - Status: {3}", item.Id, item.FirstName, item.LastName, item.SyncStatus);
                        }

                        //We can use WriteItemChanges() - writes any in-memory item changes to the table
                        //encTable.WriteItemChanges();

                        //OR WriteChangesAndFlush() writes any in-memory items to the table, and then drops any in-memory items and/or in-memory index of the table
                        //Normally, only items that are out-of-sync with the table are written, forceWriteAll causes all items (whether they have changed or not)
                        //  to be written
                        encTable.WriteChangesAndFlush(forceWriteAll: true);

                        //How many items in memory now?
                        Console.WriteLine("After WriteChangesAndFlush() there are now {0} items in memory.", encTable.TempItems.Count());

                        //How many records in the table?
                        numRecords = SampleDataItem.GetNumRecords(dbConn, encTable.TableName);
                        Console.WriteLine("After WriteChangesAndFlush() there are now {0} records in the table.", numRecords.ToString());
                    }

                    //Reading and searching for items/records
                    using (var encTable = new EncryptedTable <SampleDataItem>(myApp.AppCryptEngine, dbConn)) {
                        //Doing a GetItems() with an empty TableSearch (like the line below) will get all items
                        List <SampleDataItem> allItems = encTable.GetItems(new TableSearch());

                        foreach (var item in allItems)
                        {
                            Console.WriteLine("In table: ID#{0} {1} {2}", item.Id, item.FirstName, item.LastName);
                        }

                        //Let's just get one item - exceptionOnMissingItem: true will throw an exception if the item wasn't found
                        // in the table; with exceptionOnMissingItem: false, we will just get a null
                        SampleDataItem singleItem = encTable.GetItem(allItems.First().Id, exceptionOnMissingItem: true);
                        Console.WriteLine("Found via ID: ID#{0} {1} {2}", singleItem.Id, singleItem.FirstName, singleItem.LastName);

                        //Because we did a full table GetItems() above, we should have a nice, searchable index of all of the
                        // items in the table.  But let's check it and re-build if necessary
                        encTable.CheckFullTableIndex(rebuildIfExpired: true);

                        //Otherwise, we could just force a rebuild of the searchable index
                        //  encTable.BuildFullTableIndex();

                        //So, the easy way to find matching items, based on the full table index is to pass in a TableSearch
                        List <SampleDataItem> matchingItems = encTable.GetItems(new TableSearch {
                            SearchType = TableSearchType.MatchAll,  //Items must match all search criteria
                            MatchItems =
                            {
                                new TableSearchItem("LastName",  "Johnson", SearchItemMatchType.IsEqualTo),
                                new TableSearchItem("FirstName", "Ned",     SearchItemMatchType.DoesNotContain)
                            }
                        });
                        foreach (var item in matchingItems)
                        {
                            Console.WriteLine("Found via search: ID#{0} {1} {2}", item.Id, item.FirstName, item.LastName);
                        }

                        //Let's see what is in this "full table index" anyway
                        foreach (var item in encTable.FullTableIndex.Index)
                        {
                            Console.WriteLine("Indexed item ID: " + item.Key.ToString());
                            foreach (var value in item.Value)
                            {
                                Console.WriteLine("  - Searchable value: {0} = {1}", value.Key ?? "", value.Value ?? "");
                            }
                        }

                        //Let's remove/delete a record from the table (with immediate removal)
                        Console.WriteLine("Deleting record: ID#{0} {1} {2}", singleItem.Id, singleItem.FirstName, singleItem.LastName);
                        encTable.RemoveItem(singleItem.Id, immediateWriteToTable: true);

                        //Let's see what is actually in the table
                        Console.WriteLine("Records in the table " + encTable.TableName + " - ");
                        sql = "select * from " + encTable.TableName;
                        using (var cmd = new SqliteCommand(sql, dbConn)) {
                            using (SqliteDataReader reader = cmd.ExecuteReader()) {
                                while (reader.Read())
                                {
                                    var record = new StringBuilder();
                                    foreach (Portable.Data.Sqlite.TableColumn column in encTable.TableColumns.Values.OrderBy(tc => tc.ColumnOrder))
                                    {
                                        if (column.ColumnName == "Id")
                                        {
                                            record.Append(column.ColumnName + ": " + reader[column.ColumnName].ToString());
                                        }
                                        else
                                        {
                                            record.Append(" - " + column.ColumnName + ": " + (reader[column.ColumnName].ToString() ?? ""));
                                        }
                                    }
                                    Console.WriteLine(record.ToString());
                                }
                            }
                        }
                    }
                }

                #endregion

                Console.WriteLine("Done.");

                //Pop up a message saying we are done
                MessageBox.Show("If you can see this message, then the sample Portable.Data.Sqlite code ran correctly. " +
                                "Take a look at the code in the 'MainWindow.xaml.cs' file, and compare it to what you are seeing in the IDE Output window. " +
                                "And have a nice day...",
                                "All Done! - Check the Output window", MessageBoxButton.OK, MessageBoxImage.Information);
            }
            catch (Exception ex) {
                MessageBox.Show("An error occurred: " + ex.Message + "\n\nDetails:\n" + ex.ToString(), "ERROR",
                                MessageBoxButton.OK, MessageBoxImage.Error);
            }
            #endregion
        }