Frage

Ok, ich würde wirklich gerne wissen, wie Experte MVVM Entwickler einen Openfile Dialog in WPF behandeln.

Ich will nicht wirklich in meinem Viewmodel tun (wo ‚Durchsuchen‘ über eine DelegateCommand verwiesen wird)

void Browse(object param)
{
    //Add code here
    OpenFileDialog d = new OpenFileDialog();

    if (d.ShowDialog() == true)
    {
        //Do stuff
    }
}

Weil ich glaube, das geht gegen MVVM Methodik.

Was kann ich tun?

War es hilfreich?

Lösung

Das Beste, was hier zu tun ist, einen Service nutzen.

Ein Dienst ist nur eine Klasse, die Sie von einem zentralen Repository-Dienste zugreifen, die oft einen IOC-Container. Der Service implementiert dann, was Sie wie die Openfile benötigen.

Also, vorausgesetzt, Sie ein IFileDialogService in einem Unity Container haben, könnten Sie tun ...

void Browse(object param)
{
    var fileDialogService = container.Resolve<IFileDialogService>();

    string path = fileDialogService.OpenFileDialog();

    if (!string.IsNullOrEmpty(path))
    {
        //Do stuff
    }
}

Andere Tipps

Ich habe auf einer der Antworten kommentieren würde gern, aber leider mein Ruf nicht hoch genug ist, dies zu tun.

einen Anruf wie Openfile having () verletzt das MVVM Muster, weil es eine Ansicht (Dialog) in dem View-Modell impliziert. Die View-Modell etwas wie GetFileName () aufrufen können (das heißt, wenn einfache Bindung nicht ausreichend ist), aber es sollte nicht, wie der Dateiname erhalten wird.

Ich verwende eine Dienstleistung, die ich zum Beispiel in den Konstruktor meiner Ansichtsmodell passieren kann oder über Dependency Injection lösen. z.

public interface IOpenFileService
{
    string FileName { get; }
    bool OpenFileDialog()
}

und eine Klasse ihrer Umsetzung, Openfile unter der Haube verwenden. Im Ansichtsmodell, verwende ich nur die Schnittstelle und kann somit verspotten / ersetzen, wenn nötig.

Das Ansichtsmodell sollte nicht Dialoge öffnen oder sogar von ihrer Existenz wissen. Wenn die VM in einem separaten DLL untergebracht ist, sollte das Projekt nicht einen Verweis auf PresentationFramework hat.

Ich mag für gemeinsame Dialoge eine Hilfsklasse in der Ansicht verwenden.

Die Helfer-Klasse stellt einen Befehl (kein Ereignis), die das Fenster in XAML bindet. Dies bedeutet die Verwendung von RelayCommand innerhalb der Ansicht. Die Helfer-Klasse ist ein DepencyObject, so dass es zu der Ansicht Modell binden kann.

class DialogHelper : DependencyObject
{
    public ViewModel ViewModel
    {
        get { return (ViewModel)GetValue(ViewModelProperty); }
        set { SetValue(ViewModelProperty, value); }
    }

    public static readonly DependencyProperty ViewModelProperty =
        DependencyProperty.Register("ViewModel", typeof(ViewModel), typeof(DialogHelper),
        new UIPropertyMetadata(new PropertyChangedCallback(ViewModelProperty_Changed)));

    private static void ViewModelProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (ViewModelProperty != null)
        {
            Binding myBinding = new Binding("FileName");
            myBinding.Source = e.NewValue;
            myBinding.Mode = BindingMode.OneWayToSource;
            BindingOperations.SetBinding(d, FileNameProperty, myBinding);
        }
    }

    private string FileName
    {
        get { return (string)GetValue(FileNameProperty); }
        set { SetValue(FileNameProperty, value); }
    }

    private static readonly DependencyProperty FileNameProperty =
        DependencyProperty.Register("FileName", typeof(string), typeof(DialogHelper),
        new UIPropertyMetadata(new PropertyChangedCallback(FileNameProperty_Changed)));

    private static void FileNameProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Debug.WriteLine("DialogHelper.FileName = {0}", e.NewValue);
    }

    public ICommand OpenFile { get; private set; }

    public DialogHelper()
    {
        OpenFile = new RelayCommand(OpenFileAction);
    }

    private void OpenFileAction(object obj)
    {
        OpenFileDialog dlg = new OpenFileDialog();

        if (dlg.ShowDialog() == true)
        {
            FileName = dlg.FileName;
        }
    }
}

Die Hilfsklasse muss einen Verweis auf die Ansichtsmodell-Instanz. Finden Sie in der Ressource-Wörterbuch. Kurz nach Konstruktion wird die Ansichtsmodell Eigenschaft festgelegt (in der gleichen Zeile des XAML). Dies ist, wenn die Eigenschaft File-Namen auf der Hilfsklasse auf die Eigenschaft File-Namen auf dem View-Modell gebunden ist.

<Window x:Class="DialogExperiment.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DialogExperiment"
        xmlns:vm="clr-namespace:DialogExperimentVM;assembly=DialogExperimentVM"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <vm:ViewModel x:Key="viewModel" />
        <local:DialogHelper x:Key="helper" ViewModel="{StaticResource viewModel}"/>
    </Window.Resources>
    <DockPanel DataContext="{StaticResource viewModel}">
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="File">
                <MenuItem Header="Open" Command="{Binding Source={StaticResource helper}, Path=OpenFile}" />
            </MenuItem>
        </Menu>
    </DockPanel>
</Window>

einen Dienst zu haben ist wie oben öffnet eine Ansicht von Viewmodel. Ich habe eine Abhängigkeitseigenschaft in Aussicht, und auf der chnage der Immobilie, ich öffne File-Dialog und den Pfad lesen, die Eigenschaft aktualisieren und damit die gebundene Eigenschaft der VM

Ich habe es für mich auf diese Weise gelöst:

  • In Ansichtsmodell Ich habe eine Schnittstelle und arbeitet mit ihm definiert in Ansichtsmodell
  • In ich diese Schnittstelle implementiert haben.

CommandImpl wird in nachfolgenden Code nicht implementiert.

Ansichtsmodell:

namespace ViewModels.Interfaces
{
    using System.Collections.Generic;
    public interface IDialogWindow
    {
        List<string> ExecuteFileDialog(object owner, string extFilter);
    }
}

namespace ViewModels
{
    using ViewModels.Interfaces;
    public class MyViewModel
    {
        public ICommand DoSomeThingCmd { get; } = new CommandImpl((dialogType) =>
        {
            var dlgObj = Activator.CreateInstance(dialogType) as IDialogWindow;
            var fileNames = dlgObj?.ExecuteFileDialog(null, "*.txt");
            //Do something with fileNames..
        });
    }
}

Ausblick:

namespace Views
{
    using ViewModels.Interfaces;
    using Microsoft.Win32;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;

    public class OpenFilesDialog : IDialogWindow
    {
        public List<string> ExecuteFileDialog(object owner, string extFilter)
        {
            var fd = new OpenFileDialog();
            fd.Multiselect = true;
            if (!string.IsNullOrWhiteSpace(extFilter))
            {
                fd.Filter = extFilter;
            }
            fd.ShowDialog(owner as Window);

            return fd.FileNames.ToList();
        }
    }
}

XAML:

<Window

    xmlns:views="clr-namespace:Views"
    xmlns:viewModels="clr-namespace:ViewModels"
>    
    <Window.DataContext>
        <viewModels:MyViewModel/>
    </Window.DataContext>

    <Grid>
        <Button Content = "Open files.." Command="{Binding DoSomeThingCmd}" CommandParameter="{x:Type views:OpenFilesDialog}"/>
    </Grid>
</Window>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top