Xamarin.Forms 目录选择器

3
我希望能够将文件保存在用户选择的文件夹中,因此我想向用户提供一个目录列表,让用户能够选择他想要导出数据的目录。不幸的是,我没有找到任何目录/文件夹选择器的示例,我只找到了一个对我没有用处的文件选择器。

https://github.com/jfversluis/FilePicker-Plugin-for-Xamarin-and-Windows

是否有适用于Xamarin.Forms的选取文件夹组件?实际上我只是在做Android,但我们使用Xamarin.forms。

2个回答

3

我想不到任何一个。

有了netstandard,一切都更加简单,因为您可以使用经典的c#文件API来获取文件夹。

您只需要知道特殊文件夹与Android文件夹之间的映射关系(例如):

System.Environment.SpecialFolder    Path
ApplicationData                     INTERNAL_STORAGE/.config
Desktop                             INTERNAL_STORAGE/Desktop
LocalApplicationData                INTERNAL_STORAGE/.local/share
MyDocuments                         INTERNAL_STORAGE
MyMusic                             INTERNAL_STORAGE/Music
MyPictures                          INTERNAL_STORAGE/Pictures
MyVideos                            INTERNAL_STORAGE/Videos
Personal                            INTERNAL_STORAGE

来源: https://learn.microsoft.com/zh-cn/xamarin/android/platform/files/

iOS的内容相同:

https://learn.microsoft.com/zh-cn/xamarin/ios/app-fundamentals/file-system

但它真的很容易实现,只需枚举所有文件夹并在ListView中显示他们即可。

编辑:实现更多细节。

事实上,你要编写一个 "目录浏览器" 十分简单,以下是概念。

  • 在你的 Page 中有一个 ListView
  • 在你的 Page 中有一个 Cancel 按钮和一个 Select 按钮
  • 在你的 ViewModel 中有一个 CurrentPath
  • CurrentPath 绑定到你的页面的 Title
  • 在你的 ViewModel 中有一个 List<DirectoryViewModel> Directories

每当用户点击列表中的项目时:

  • 将目录名称添加到您的当前路径中
  • 从新路径获取所有目录,并更新您的目录属性 (别忘了 RaisePropertyChange(nameof(Directories)))
  • ListView 将相应地更新

每次返回时:

  • 删除当前路径的最后一部分
  • 同上

如果到达根路径 " / ",则在点击返回时不执行任何操作。

哦,你可以使用这个 Grid 组件来代替 ListView,看起来更漂亮 ;)。

https://github.com/roubachof/Sharpnado.Presentation.Forms#grid-Layout


1
谢谢您的回复,但我需要一个GUI界面吗?我必须自己创建GUI界面吗? - ertan2002
1
是的,你有,但它比起一开始看起来要简单得多(请参见我的编辑答案)。 - Roubachof

0

您可以编辑此内容以使其正常工作。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Java.IO;
using Java.Util;

namespace Android.Basic.IO
{
    
    public class DirectoryPicker : ListActivity
    {


        public const String START_DIR = "startDir";
        public const String ONLY_DIRS = "onlyDirs";
        public const String SHOW_HIDDEN = "showHidden";
        public const String CHOSEN_DIRECTORY = "chosenDir";
        public const int PICK_DIRECTORY = 43522;
        private File dir;
        private Boolean showHidden = false;
        private bool onlyDirs = true;
        public override void OnCreate(Bundle savedInstanceState, PersistableBundle persistentState)
        {
            base.OnCreate(savedInstanceState, persistentState);
            Bundle extras = Intent.Extras;
            dir = OS.Environment.ExternalStorageDirectory;
            if (extras != null)
            {
                String preferredStartDir = extras.GetString(START_DIR);
                showHidden = extras.GetBoolean(SHOW_HIDDEN, false);
                onlyDirs = extras.GetBoolean(ONLY_DIRS, true);
                if (preferredStartDir != null)
                {
                    File startDir = new File(preferredStartDir);
                    if (startDir.IsDirectory)
                    {
                        dir = startDir;
                    }
                }
            }

            SetContentView(Resource.Layout.folder_chooser_activity);
            var title = dir.AbsolutePath.ToString();
            Title = (title);
            Button btnChoose = (Button)FindViewById(Resource.Id.btnChoose);
            String name = dir.Name;
            if (name.Length == 0)
                name = "/";
            btnChoose.Text = ("Choose " + "'" + name + "'");
            btnChoose.Click += delegate
              {
                  returnDir(dir.AbsolutePath);
              };
            ListView lv = this.ListView;
            lv.TextFilterEnabled = (true);

            if (!dir.CanRead())
            {
                Context context = ApplicationContext;
                String msg = "Could not read folder contents.";
                Toast.MakeText(context, msg, ToastLength.Long).Show();
                return;
            }
            var files = filter(dir.ListFiles(), onlyDirs, showHidden);
            String[] names = Names(files);
            ListAdapter = (new ArrayAdapter<String>(this, Resource.Layout.folder_chooser_item, names));
            lv.ItemClick += (ff, gg) =>
            {
                var position = gg.Position;
                if (!files[gg.Position].IsDirectory)
                    return;
                String path = files[position].AbsolutePath;
                var intent = new Intent(this, typeof(DirectoryPicker));
                intent.PutExtra(DirectoryPicker.START_DIR, path);
                intent.PutExtra(DirectoryPicker.SHOW_HIDDEN, showHidden);
                intent.PutExtra(DirectoryPicker.ONLY_DIRS, onlyDirs);
                StartActivityForResult(intent, PICK_DIRECTORY);
            };

        }

        protected void OnActivityResult(int requestCode, int resultCode, Intent data)
        {
            if (requestCode == PICK_DIRECTORY && resultCode == (int)Result.Ok)
            {
                Bundle extras = data.Extras;
                String path = (String)extras.Get(DirectoryPicker.CHOSEN_DIRECTORY);
                returnDir(path);
            }
        }

        private void returnDir(String path)
        {
            Intent result = new Intent();
            result.PutExtra(CHOSEN_DIRECTORY, path);
            SetResult(Result.Ok, result);
            Finish();
        }


        public List<File> filter(File[] file_list, bool onlyDirs, bool showHidden)
        {
            var files = new List<File>();
            foreach (var file in file_list)
            {
                if (onlyDirs && !file.IsDirectory)
                    continue;
                if (!showHidden && file.IsHidden)
                    continue;
                files.Add(file);
            }
            Collections.Sort(files);
            return files;
        }

        public String[] Names(List<File> files)
        {
            String[] names = new String[files.Count];
            int i = 0;
            foreach (var file in files)
            {
                names[i] = file.Name;
                i++;
            }
            return names;
        }
    }
}

以结果的形式启动活动,然后在OnActivityResult中捕获

if (requestCode == DirectoryPicker.PICK_DIRECTORY && resultCode == Result.Ok)
            {
                Bundle extras = data.Extras;
                String path = (String)extras.Get(DirectoryPicker.CHOSEN_DIRECTORY);
                // do stuff with path
            }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接