Xamarin.Forms 目录选取器
Xamarin.Forms Directory Picker
我想将文件保存在用户选择的文件夹中,这就是为什么我想向用户提供目录列表,用户将能够选择他想要导出数据的目录。不幸的是,我找不到 directory/folder 选择器的任何示例,我只是找到了一个对我没有用的文件选择器..
https://github.com/jfversluis/FilePicker-Plugin-for-Xamarin-and-Windows
是否有为 Xamarin.Forms 选择文件夹的组件?实际上我只是在做 Android 但我们使用 Xamarin.forms
有none我能想到的。
使用 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://docs.microsoft.com/en-US/xamarin/android/platform/files/
与 ios 相同:
https://docs.microsoft.com/en-US/xamarin/ios/app-fundamentals/file-system
不过实现起来真的很简单,枚举所有的文件夹,然后在一个ListView中显示即可。
编辑:关于实施的更多细节。
其实你要编码一个"directory explorer",很简单,概念就在这里。
- 您的
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
您可以对其进行编辑以使其正常工作..
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;
}
}
}
作为结果启动activity然后在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
}
我想将文件保存在用户选择的文件夹中,这就是为什么我想向用户提供目录列表,用户将能够选择他想要导出数据的目录。不幸的是,我找不到 directory/folder 选择器的任何示例,我只是找到了一个对我没有用的文件选择器..
https://github.com/jfversluis/FilePicker-Plugin-for-Xamarin-and-Windows
是否有为 Xamarin.Forms 选择文件夹的组件?实际上我只是在做 Android 但我们使用 Xamarin.forms
有none我能想到的。 使用 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://docs.microsoft.com/en-US/xamarin/android/platform/files/
与 ios 相同:
https://docs.microsoft.com/en-US/xamarin/ios/app-fundamentals/file-system
不过实现起来真的很简单,枚举所有的文件夹,然后在一个ListView中显示即可。
编辑:关于实施的更多细节。
其实你要编码一个"directory explorer",很简单,概念就在这里。
- 您的
Page
中有一个 - 您的
Page
中有一个 - 您的
ViewModel
中有一个 - 您将
CurrentPath
绑定到主页的Title
- 您的
ViewModel
中有一个
ListView
Cancel
按钮和一个 Select
按钮
CurrentPath
List<DirectoryViewModel> Directories
每次用户单击列表中的项目时:
- 您在当前路径中添加目录名称
- 您从新路径获取所有目录,并更新您的目录 属性(不要忘记
RaisePropertyChange(nameof(Directories))
) ListView
会相应更新
每次返回:
- 您删除了当前路径的最后一部分
- 和以前一样
如果你到达根路径“/”,点击返回时你什么都不做。
哦,你可以使用这个 Grid
组件来代替 ListView
,会更好 ;)
https://github.com/roubachof/Sharpnado.Presentation.Forms#grid-Layout
您可以对其进行编辑以使其正常工作..
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;
}
}
}
作为结果启动activity然后在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
}