如何在 UWP 应用程序中构建我的 SQLite 连接字符串?

How can I build my SQLite connection string in a UWP App?

在我的 Windows 表单应用程序中,我能够像这样构建我的 SQLite 连接字符串(在通过添加 > 现有项将 .db 文件添加到我的项目之后):

string connStr = string.Format(@"Data source={0}F4F.db", Application.StartupPath);

所以我在我的 UWP 项目中尝试了同样的事情,代码如下:

string connStr = string.Format(@"Data source={0}Cartographer.db", Application.StartupPath);
SqliteConnection conn = new SqliteConnection(connStr);

...但是没有“StartupPath”属性。我应该改用什么?

这些是 Application 对象的可用成员:

我应该使用“当前”吗?

更新

为了回应 Peter 的回答,并作为我对该回答的评论的补充,这是我现在拥有的代码:

public sealed partial class MainPage : Page
{
        StorageFolder folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
        string connStrBase = @"Data source={0}Cartographer.db";
        string connStr = string.Empty;
        string path = string.Empty;    
        . . .
}

. . .

path = folder.Path;
connStr = string.Format(connStrBase, path);

...我至少接近正确了吗?

要对打包为应用程序一部分的文件进行读写访问,您需要将其复制到应用程序第一个 运行 上的 ApplicationData.LocalFolder 目录,然后您可以从那里更新它。然后您可以使用 LocalFolder.Path 属性 以正确的位置初始化您的连接字符串。原始文件将位于您的 Package.InstalledLocation.

这是一个基本示例,使用帮助程序 class,您可以使用它来将任何文件从包中的任意位置复制到本地文件夹中的镜像位置,然后 return结果文件名。

该示例是异步的,以防您在启动等过程中复制大文件,但如果您只需要包目录中的文件,它可以很容易地同步。此外,即使 API 是异步的,如果您愿意,也可以 100% 安全地阻止它(如下图所示)。

class LocalDataUtils
{
    static readonly string destinationDirectory = 
        ApplicationData.Current.LocalFolder.Path;
    static readonly string sourceDirectory = 
        Package.Current.InstalledPath;

    static Dictionary<string, TaskCompletionSource<string>> fileCompletionTasks = 
        new Dictionary<string, TaskCompletionSource<string>>();

    public static Task<string> GetFilenameAsync(string relativePath)
    {
        TaskCompletionSource<string> completion;

        if (!fileCompletionTasks.TryGetValue(relativePath, out completion))
        {
            lock (fileCompletionTasks)
            {
                // Check again in case there was a race.
                if (!fileCompletionTasks.TryGetValue(relativePath, out completion))
                {
                    completion = new TaskCompletionSource<string>();
                    fileCompletionTasks.Add(relativePath, completion);

                    // This is async in case you ever need to copy from locations 
                    // other than your local folders or you are copying files
                    // that might take a while.
                    // You can simplify and make it not-async if you like.
                    Task.Run(() => CopyFileAndGetFilename(relativePath, completion));
                }
            }
        }

        return completion.Task;
    }

    static void CopyFileAndGetFilename(string relativePath, 
        TaskCompletionSource<string> completion)
    {
        try
        {
            // Also a fun movie :)
            var finalDestination = Path.Combine(destinationDirectory, relativePath);

            if (!File.Exists(finalDestination))
            {
                var originalLocation = Path.Combine(sourceDirectory, relativePath);
                Directory.CreateDirectory(Path.GetDirectoryName(finalDestination));
                File.Copy(originalLocation, finalDestination);
            }

            completion.SetResult(finalDestination);
        }
        catch (Exception ex)
        {
            completion.SetException(ex);
        }
    }
}

使用起来非常简单:

var name = await LocalDataUtils.GetFilenameAsync(@"Database\test.db");
var text = File.ReadAllText(name);
Debug.Write(text);

// Note: no 'await' here for illustrative purposes; subsequent calls
// for the same file will always return immediately.
var otherNameTask = LocalDataUtils.GetFilenameAsync(@"Database\test.db");
Debug.Assert(otherNameTask.IsCompletedSuccessfully);

// Don't call 'await' and instead block on the 'Result'
// This is not safe in general for async methods, but is fine in this case.
var name2 = LocalDataUtils.GetFilenameAsync(@"Assets\StoreLogo.png").Result;
var size = new FileInfo(name2).Length;
Debug.WriteLine($"{Path.GetFileName(name2)} is {size} bytes long.");