Передавать файл между страницами - UWP C# - PullRequest
0 голосов
/ 26 мая 2020

Мне интересно, как лучше всего передавать файл между страницами в приложении UWP?

У меня есть приложение UWP с двумя страницами. На первой странице я предлагаю пользователю открыть файл с помощью filepicker и загрузить этот файл в медиаплеер.

Я хочу передать тот же файл на вторую страницу, когда пользователь переходит туда. В настоящее время я передаю файл в виде строки, которую затем пытаюсь загрузить как файл хранилища, используя GetFileFromPathAsyn c.

В настоящее время это работает, поскольку я могу загрузить файл на второй странице, но для этого требуется что пользователь предоставляет широкий доступ к файловой системе.

Код на странице 1 (FileLoaded - это строка пути к файлу):

private async void TranscodeMedia_Click(object sender, RoutedEventArgs e)
        {
            AppWindow appWindow = await AppWindow.TryCreateAsync();
            Frame appWindowContentFrame = new Frame();
            appWindowContentFrame.Navigate(typeof(TranscodeMedia), FileLoaded);

Код на странице 2:

    protected override async void OnNavigatedTo(NavigationEventArgs e)
    {
        var fileTransfer = e.Parameter.ToString();

        FileName.Text = fileTransfer;

        StorageFile PassedFile = await StorageFile.GetFileFromPathAsync(fileTransfer);

Мне интересно, это лучший способ передавать файл между страницами? Я бы предпочел не требовать от пользователя предоставления широкого доступа к системе к приложению, если это возможно. Мы очень ценим любую помощь, которую вы можете оказать!

Ответы [ 2 ]

1 голос
/ 28 мая 2020

Лучший и самый стандартный способ в C # / WPF / UWP - использовать стандартный шаблон, который состоит из общего класса ViewModel (который содержит все общие данные приложения, которые вы хотите использовать на уровне logi c). , вставьте как поле в stati c MainPage (или даже в класс App.xaml.cs).

Я всегда делаю это так:

1) Я использую автоматически созданную MainPage в качестве «оболочки» приложения со свойством AppViewModel. К MainPage (и, следовательно, к AppViewModel) можно получить доступ из любого места в приложении, задав себя как поле stati c в своем собственном классе (поле «Current» stati c может вызываться из любого места в приложении ... даже в классе MessageDialog!).

Это код для MainPage (или страницы оболочки, на которой вы sh, но я предлагаю сделать вот так, это довольно стандартный способ, используемый даже Microsoft), проще, чем вы думаете:

public sealed partial class MainPage : Page
{
    public AppViewModel ViewModel { get; set; } = new AppViewModel();
    public static MainPage Current { get; set; }

    public MainPage()
    {
        this.InitializeComponent();
        Current = this;
    }
}

ЭТО Уловка: сделать страницу stati c в одном поле в собственном классе, так что это поле stati c будет УНИКАЛЬНЫМ во всем приложении (это одна из основных особенностей слова «stati c») и, таким образом, позвонив по номеру MainPage.Current.ViewModel, вы можете немедленно получить любые данные (в вашем конкретном случае c, StorageFile), хранящиеся там.

2) Сам AppViewModel является классом который должен реализовывать интерфейс INotifyPropertyChanged, чтобы включить привязываемые свойства и функции. Среди Windows разработчиков принято создавать базовый класс, реализующий его, а затем извлекать из него все классы, которым нужны связываемые (т. Е. Наблюдаемые) свойства.

Вот как именно Microsoft создает it:

public class BaseBind : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    protected bool SetProperty<T>(ref T storage, T value,
        [CallerMemberName] String propertyName = null)
    {
        if (object.Equals(storage, value)) return false;
        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}

Затем вы наследуете от него класс AppViewModel (и все другие классы модели и модели представления)… заполняя его всеми общими свойствами, которые вам нужно разделить между страницами. Я даже добавил производное свойство, чтобы показать, как вы можете делиться даже несколькими типами данных одновременно, и функцию:

public class AppViewModel : BaseBind
{
    public AppViewModel()
    {
        // Usually we initialize all the starting data here, in the viewmodel constructor...
    }

    // All common app data
    private string sampleCommonString;
    public String SampleCommonString
    {
        get { return sampleCommonString; }
        set { SetProperty(ref sampleCommonString, value); OnPropertyChanged(nameof(SampleDerivedProperty1)); OnPropertyChanged(nameof(SampleDerivedProperty2)); }
    }

    public String SampleDerivedProperty1 =>  "return something based on SampleCommonString";

    public String SampleDerivedProperty2
    {
        get
        {
            // evaluate in some way SampleCommonString...

            return "Same thing as SampleDerivedProperty1, but it allows to add more than just one istruction";
        }
    }

    // This is a property that you can use for functions and internal logic… but it CAN'T be binded to the UI directly
    public String SampleNOTBindableProperty { get; set; }

    public void SampleFunction()
    {
        // Insert code, that needs to interact with all the data contained in the viewmodel itself, here...

        // The function has to be with NO parameters, in order to work with simple {x:Bind} markup.
        // If your function has to access some specific data, you can create a new bindable (or non) property, just as the ones above, and memorize the data there.
    }
}

3) Затем, чтобы получить доступ ко всему этому из другого Page, просто создайте на этой странице поле AppViewModel, ссылаясь на модель просмотра, содержащуюся на главной странице c:

public sealed partial class SecondPage : Page
{
    public AppViewModel ViewModel => MainPage.Current.ViewModel;

    public SecondPage()
    {
        this.InitializeComponent();
    }
}

... и вы можете легко привязать свойства элементов управления XAML к AppViewModel сам:

<TextBlock Text="{x:Bind ViewModel.SampleCommonString, Mode=OneWay}"/>
<TextBox Text="{x:Bind ViewModel.SampleCommonString, Mode=TwoWay}"/>
<Button Content="Sample content" Click="{x:Bind ViewModel.SampleFunction}"/>

(Mode=OneWay - для привязки в реальном времени, чтобы свойство немедленно обновлялось даже в пользовательском интерфейсе, а Mode=TwoWay - для тех свойств, которые можно редактировать из c).

В этом режиме вы сможете отображать данные и все их изменения в реальном времени!

Итак ... это способ сохранить все данные приложения во время выполнения правильным и гибким способом ... изучая его и практикуясь, в будущем вы будете использовать этот шаблон даже более разумным способом, создавая модели просмотра для каждого obj ect вашего приложения (например: если ваше приложение должно хранить данные клиентов вашей компании, у вас будет класс «CustomerViewModel», производный от класса BaseBind, со всеми данными клиента в нем) и создание списков, например ObservableCollection<SampleViewModel> для хранения всех из них (ObservableCollection<t> - это тип коллекции, который имеет встроенный механизм для обработки изменений списка, таких как добавление, удаление и изменение порядка элементов списка). Затем вы свяжете каждую наблюдаемую коллекцию со свойством ItemsSource элемента управления, который наследуется от класса ListBase (типично: ListView или GridView), создав DataTemplate для отображения каждого элемента списка, как в этом примере:

<Page
    xmlns:vm="using:SampleApp.ViewModelsPath"

    <Grid>
    <ListView ItemsSource="{x:Bind ViewModel.SampleListOfObjectViewModel, Mode=OneWay}">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="vm:SampleObjectViewModel">
                <StackPanel>
                    <TextBlock Text="{x:Bind SampleObjectProperty1, Mode=OneWay}"/>
                    <TextBlock Text="{x:Bind SampleObjectProperty2, Mode=OneWay}"/>
                    <Button Click="{x:Bind SampleObjectFunction}"/>
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>
</Page>

... и все отображаемые данные будут обновляться в реальном времени всякий раз, когда вы их измените!

Надеюсь, все это поможет вам расширить свои знания о том, как готовить WPF / UWP logi c layer , потому что все это работает примерно одинаково даже для приложений WPF (то есть старых настольных программ).

С уважением

0 голосов
/ 27 мая 2020

Есть несколько других способов реализовать ваше требование о доступе к одному и тому же файлу на разных страницах. Но для вашего сценария вы можете использовать Список будущего доступа в своем приложении UWP.

Выбирая файлы и папки, ваш пользователь предоставляет вашему приложению разрешение на доступ к элементам, которые в противном случае могут быть недоступны. . Если вы добавите эти элементы в свой список будущего доступа , вы сохраните это разрешение, когда ваше приложение захочет получить доступ к этим элементам позже.

Вот пример кода, который я сделал

На первой странице:

        FileOpenPicker picker = new FileOpenPicker();

        picker.FileTypeFilter.Add("*");

        StorageFile file = await picker.PickSingleFileAsync();

        if (file != null) 
        {
            // add file to the Future Access list
            var storageItemAccessList = Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList;
            // this token is the key to get the file.
            string FALToken = storageItemAccessList.Add(file, "mediaFile");
            // in your real scenario, you need to save the token and pass it when you nee
            this.Frame.Navigate(typeof(TestPage), FALToken);
        }

На второй странице:

   protected override async void OnNavigatedTo(NavigationEventArgs e)
    {
        string token = (string)e.Parameter;

        var storageItemAccessList = StorageApplicationPermissions.FutureAccessList;

        StorageFile retrievedFile = await storageItemAccessList.GetFileAsync(token);


    }

Таким образом, вам не нужен широкий доступ к файловой системе, если вы используете Future-access list , чтобы сохранить права доступа к файлам.

Для получения более подробной информации обратитесь к этому документу: Отслеживание недавно использованных файлов и папок

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...