Mono for Android:显示文件选择器?

时间:2012-07-27 15:55:47

标签: c# java android mono xamarin.android

我正在尝试使用this tutorial将代码从Mono for Android移植到C#。这是我的代码:

FileLayout.axml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:layout_width="fill_parent">
    <TextView
        android:text="@+id/TextView01"
        android:id="@+id/TextView01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:singleLine="true"
        android:textStyle="bold"
        android:layout_marginTop="5dip"
        android:layout_marginLeft="5dip" />
    <TextView
        android:text="@+id/TextView02"
        android:id="@+id/TextView02"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dip" />
</LinearLayout>

FileArrayAdapter.cs

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;

namespace FileChooser
{
    public class FileArrayAdapter : ArrayAdapter<Option>
    {

        private Context c;
        private int id;
        private List<Option> items;

        public FileArrayAdapter(Context context, int textViewResourceId,
                List<Option> objects)
            : base(context, textViewResourceId, objects)
        {

            c = context;
            id = textViewResourceId;
            items = objects;
        }

        public Option getItem(int i)
        {
            return items[i];
        }
        public View getView(int position, View convertView, ViewGroup parent)
        {
            View v = convertView;
            if (v == null)
            {
                LayoutInflater vi = (LayoutInflater)c.GetSystemService(Context.LayoutInflaterService);
                v = vi.Inflate(id, null);
            }
            Option o = items[position];
            if (o != null)
            {
                TextView t1 = (TextView)v.FindViewById(Resource.Id.TextView01);
                TextView t2 = (TextView)v.FindViewById(Resource.Id.TextView02);

                if (t1 != null)
                    t1.Text = o.getName().ToString();
                if (t2 != null)
                    t2.Text = o.getData().ToString();

            }
            return v;
        }


    }

}

Activity1.cs:

using System;
using System.Collections;
using System.Collections.Generic;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using Android.OS;
using Java.IO;
using Environment = Android.OS.Environment;


namespace FileChooser
{
    [Activity(Label = "FileChooser", MainLauncher = true, Icon = "@drawable/icon")]
    public class Activity1 : ListActivity
    {
        private File currentDir;
        private FileArrayAdapter adapter;

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            currentDir = new File(Environment.RootDirectory.AbsolutePath);
            fill(currentDir);

        }

        private void fill(File f)
        {
            File[] dirs = f.ListFiles();

            Title = ("Current Dir: " + f.Name);
            List<Option> dir = new List<Option>();
            List<Option> fls = new List<Option>();

            try
            {
                foreach (var ff in dirs)
                    if (ff.IsDirectory)
                        dir.Add(new Option(ff.Name, "Folder", ff.AbsolutePath));
                    else
                        fls.Add(new Option(ff.Name, "File Size: " + ff.Length(), ff.AbsolutePath));


                dir.AddRange(fls);

                if (!String.Equals(f.Name, "sdcard", comparisonType: StringComparison.InvariantCultureIgnoreCase))
                    dir.Insert(0, new Option("..", "Parent Directory", f.Parent));

                adapter = new FileArrayAdapter(this, Resource.Layout.FileLayout, dir);
                this.ListAdapter = adapter;

            } 
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("Error: ", e.Message);

            }


        }



    }
}

我收到以下错误:

The program 'Mono' has exited with code 255 (0xff).

我在最后一个声明之后放了一个断点。这是我的局部变量的一个情景:enter image description here

2 个答案:

答案 0 :(得分:2)

我可能会在这里离开,但我不久前写了一个简单的轻量级文件选择小部件。

package com.skype.widget;
import java.io.File;
import java.util.ArrayList;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

/**
 * General purpose, light-weight file explorer widget.<br>
 * Upon initialization, it will point at the root of the filesystem, at which
 * point you can manipulate it with {@link #browseToLocation(String)}
 * 
 * @author Aleksandar Milenkovic
 */

public class FileBrowser extends ListView implements AdapterView.OnItemClickListener
{
/**
 * Use display mode to toggle between absolute and relative display modes.
 */
public enum DISPLAYMODE
{
    ABSOLUTE, RELATIVE;
}

/**
 * Use work mode to toggle between folder-only and files-and-folders mode.
 */
public enum WORKMODE
{
    FOLDER_ONLY, FILE_AND_FOLDER;
}

public static final String      ROOT        = "/";
public static final String      LOGTAG      = "FileBrowser";

@SuppressWarnings("unused")
private Context                 context;

private final DISPLAYMODE       displayMode = DISPLAYMODE.RELATIVE;
private WORKMODE                workMode    = WORKMODE.FILE_AND_FOLDER;
private ArrayList<String>       directoryEntries;
private File                    currentDirectory;
private ArrayAdapter<String>    mAdapter;


public FileBrowser(Context context)
{
    this(context, null, 0);
}

public FileBrowser(Context context, AttributeSet attrs, int defStyle)
{
    super(context, attrs, defStyle);
    this.context = context;
    //init members
    directoryEntries = new ArrayList<String>();
    mAdapter = new ArrayAdapter<String>(context, R.layout.file_browser_entry, this.directoryEntries);
    this.setAdapter(mAdapter);

    //browse to root
    browseToLocation(ROOT);

    //refresh UI elements
    mAdapter.notifyDataSetChanged();
    setOnItemClickListener(this);
}

public FileBrowser(Context context, AttributeSet attrs)
{
    this(context, attrs, 0);
}


/**
 * This function browses to the root-directory of the file-system.
 * 
 * @param location
 *            the absolute path you want to browse to.
 */
public void browseToLocation(String location)
{
    browseTo(new File(location));
}

/**
 * This function browses up one level according to the field:
 * currentDirectory
 */
private void upOneLevel()
{
    Log.d(LOGTAG, "upOneLevel()");
    if (currentDirectory.getAbsolutePath() == ROOT) return;
    if (this.currentDirectory.getParent() != null) this.browseTo(this.currentDirectory.getParentFile());
}

private void browseTo(final File aDirectory)
{
    Log.d(LOGTAG, "browseTo()");
    if (aDirectory.isDirectory())
    {
        this.currentDirectory = aDirectory;
        fill(aDirectory.listFiles());
    } else
    {
        Log.d(LOGTAG, aDirectory.getAbsolutePath());
    }
}

private void fill(File[] files)
{
    Log.d(LOGTAG, "fill()");
    this.directoryEntries.clear();

    // Add the "." and the ".." == 'Up one level'
    this.directoryEntries.add(".");
    if (this.currentDirectory.getParent() != null) this.directoryEntries.add("..");

    switch (this.workMode)
    {
        case FOLDER_ONLY:
            switch (this.displayMode)
            {
                case ABSOLUTE:
                    for (File file : files)
                    {
                        if (file.isDirectory()) this.directoryEntries.add(file.getPath() + "/");
                    }
                    break;
                case RELATIVE: // On relative Mode, we have to add the current-path to the beginning
                    int currentPathStringLenght = this.currentDirectory.getAbsolutePath().length();
                    for (File file : files)
                    {
                        if (file.isDirectory())
                            this.directoryEntries.add(file.getAbsolutePath().substring(currentPathStringLenght) + "/");
                    }
                    break;
            }
            break;

        case FILE_AND_FOLDER:
            switch (this.displayMode)
            {
                case ABSOLUTE:
                    for (File file : files)
                    {
                        if (file.isDirectory())
                            this.directoryEntries.add(file.getPath() + "/");
                        else
                            this.directoryEntries.add(file.getPath());
                    }
                    break;
                case RELATIVE: // On relative Mode, we have to add the current-path to the beginning
                    int currentPathStringLenght = this.currentDirectory.getAbsolutePath().length();
                    for (File file : files)
                    {
                        if (file.isDirectory())
                            this.directoryEntries.add(file.getAbsolutePath().substring(currentPathStringLenght) + "/");
                        else
                            this.directoryEntries.add(file.getAbsolutePath().substring(currentPathStringLenght));
                    }
                    break;
            }
    }

}

/**
 * Internal onItemClick method that handles browsing and displaying.<br>
 * <b>Make sure to call this at the start of the outer onItemClick.</b>
 */
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
{
    String selectedFileString = directoryEntries.get(arg2);
    Log.d(LOGTAG, "onItemClick() fired!");
    if (selectedFileString.equals("."))
    {
        // Refresh
        browseTo(currentDirectory);
    } else if (selectedFileString.equals(".."))
    {
        upOneLevel();
    } else
    {
        File clickedFile = null;
        switch (displayMode)
        {
            case RELATIVE:
                clickedFile = new File(currentDirectory.getAbsolutePath() + directoryEntries.get(arg2));
                break;
            case ABSOLUTE:
                clickedFile = new File(directoryEntries.get(arg2));
                break;
        }
        if (clickedFile != null) browseTo(clickedFile);
    }
    mAdapter.notifyDataSetChanged();
    this.postInvalidate();
}

/**
 * Gets the current path in absolute form.
 * 
 * @return the absolute path pointing to the current directory.
 */
public String getCurrentPath()
{
    return currentDirectory.getAbsolutePath();
}

/**
 * Method used for setting the work mode of this widget. <br>
 * It can be either {@link WORKMODE#FILE_AND_FOLDER} or {@link WORKMODE#FOLDER_ONLY}
 * @param wm
 * the workmode to use.
 */
public void setWorkMode(WORKMODE wm)
{
    this.workMode = wm;
}

/**
 * Returns the current workmode of this widget.
 * @return
 * {@link #workMode} as {@link WORKMODE} enum
 */
public WORKMODE getWorkMode()
{
    return workMode;
}

}

用法:

 final FileBrowser fb = (FileBrowser) dialog.findViewById(R.id.folder_list);
    fb.setWorkMode(FileBrowser.WORKMODE.FOLDER_ONLY);
    fb.setOnItemClickListener(new AdapterView.OnItemClickListener()
    {
        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
        {
            fb.onItemClick(arg0, arg1, arg2, arg3);

            txt.setText(fb.getCurrentPath());
            savingPath = fb.getCurrentPath() + "/";
        }
    });

抱歉,如果那不是您想要的。

答案 1 :(得分:0)

我通过对FileArrayAdapter.cs进行更改来实现它。我没有实现ArrayAdapter,而是实现了BaseAdapter类。 。切换到正确的基类也让我意识到实现的方法中的大写是错误的。

其中一个棘手的部分是将List<Option> item转换为GetItem()方法中的Java Object

以下是修订后的代码:

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 Android.Runtime;

namespace FileChooser
{
    public class FileArrayAdapter : BaseAdapter<Option>
    {

        private Context c;
        private int id;
        private List<Option> items;

        public FileArrayAdapter(Context context, int textViewResourceId,
                List<Option> objects)

        {

            c = context;
            id = textViewResourceId;
            items = objects;
        }

        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            View v = convertView;
            if (v == null)
            {
                LayoutInflater vi = (LayoutInflater)c.GetSystemService(Context.LayoutInflaterService);
                v = vi.Inflate(id, null);
            }
            Option o = items[position];
            if (o != null)
            {
                TextView t1 = (TextView)v.FindViewById(Resource.Id.TextView01);
                TextView t2 = (TextView)v.FindViewById(Resource.Id.TextView02);

                if (t1 != null)
                    t1.Text = o.getName().ToString();
                if (t2 != null)
                    t2.Text = o.getData().ToString();

            }
            return v;
        }



        public override Option this[int position]
        {
            get { return items[position]; }
        }

        public override int Count
        {
            get { return items.Count; }
        }

        public override long GetItemId(int position)
        {
            return position;
        }

    }

}