简体   繁体   中英

WPF OpenFileDialog using MVVM (Model-View-ViewModel) in c#

How to write WPF OpenFileDialog using MVVM (Model-View-ViewModel) in c#? I have visited some websites regarding this OpenFileDialog ,but I didn't get clear idea about it. This is my code

In View.xaml :

<Window....  xmlns:VM="clr-namespace:myproject.myViewModel"
  ...  >
<Window.DataContext><VM:myViewModel/>

</Window.DataContext>
 <ItemsControl ItemsSource="{Binding mygroup}" >
        <ItemsControl.ItemTemplate >
        <DataTemplate>

                 <Grid >....

                       <TextBlock Text="Color"  Margin="20" VerticalAlignment="Center"/>
                        <ComboBox   KeyboardNavigation.TabIndex="0" Grid.Column="1" Margin="45,10,10,10" Height="30" Width="200" ItemsSource="{Binding Color}"   />
                        <TextBlock Text="Shapes" Grid.Row="1"  VerticalAlignment="Center"  />

                        <ComboBox KeyboardNavigation.TabIndex="3" Grid.Column="1" Grid.Row="1" Height="20" Width="150" SelectedIndex="0"   HorizontalContentAlignment="Right" 
                      VerticalAlignment="Center"  ItemsSource="{Binding Shapes}">
                                                            </ComboBox>

<TextBlock Text="Open Files "  VerticalAlignment="Center"      Grid.Row="0"  Grid.Column="2" Margin="10"    />
                                <TextBox  Grid.Column="3" Text="" Height="30" Grid.Row="0"   IsReadOnly="True" 
                        TextAlignment="Right" VerticalContentAlignment="Center" Width="200" />                                    <Button  Grid.Column="4"  Content="Browse"    Height="30" VerticalAlignment="Bottom"   MinWidth="41" />
                   </Grid>

 </Window>  

In Model.cs :

namespace Myproject.Models
{
  public class ProjectModel : INotifyPropertyChanged
  {
    private ObservableCollection<string> color;
    private ObservableCollection<string> shapes;
    public ObservableCollection<string> Color
{
  get { return color; }
  set
  {
    color = value;
    NotifyPropertyChanged("Color");
  }
}

public ObservableCollection<string> Shapes
{
  get { return shapes; }
  set
  {
    shapes = value;
    NotifyPropertyChanged("Shapes");
  }
}


#region INotifyPropertyChanged Members

public event PropertyChangedEventHandler PropertyChanged;

#endregion

#region Private Helpers

private void NotifyPropertyChanged(string propertyName)
{
  if (PropertyChanged != null)
  {
    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  }
}

#endregion


 }
}

In ViewModel.cs :

namespace MyProject.ViewModels    
{
  public class myProjectViewModel : INotifyPropertyChanged
  {
    private ObservableCollection<myprojectmodel> mygroup;

public ObservableCollection<myprojectmodel> Mygroup
{
  get => this.mygroup;
  set
  {
    if (Equals(value, this.mygroup)) return;
    this.mygroup = value;
    OnPropertyChanged();
  }
}

public ProjectViewModel()
{
  Mygroup = new ObservableCollection<myprojectmodel>();
  List<string> lstColor = new List<string>();
  lstCity = new List<string> {"Pink", "Blue", "Red"};
  List<string> lstShapes = new List<string>();
  lstTemperature = new List<string> {"Rectangle", "Triangle", "Circle"};
   Mygroup.Add(
    new ProjectModel
    {
      Color= new ObservableCollection<string>(lstColor),
      Shapes = new ObservableCollection<string>(lstShapes),
      });
}

public event PropertyChangedEventHandler PropertyChanged;   

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
  this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}


 }
}

How should I write code to get OpenFileDialog. I have seen this link WPF OpenFileDialog with the MVVM pattern? but I don't know how to write it for my above code. please someone help me by editing my code to get OpenFileDailog.

In my opinion this kind of things doesn't belong in to the ViewModel. It's View specific logic. The View alone handles user input and then sends it to the ViewModel. ViewModel never asks the View to do something. This would invert the dependency chain and couple the ViewModel to the View. The dependencies have to be like this: View --> ViewModel --> Model. The ViewModel doesn't even know about the type of views nor that there is a View at all.

You have to open the dialog from your view and then send the result to the view model. For this you could create a simple event handler in your code-behind and attach it to a button's click event. You take the picked file and use an ICommand to invoke eg an open file action. That's MVVM (or MVP). Separate the concerns of the views from your models.

MainWindow.xaml:

<Window x:Class="WpfOpenDialogExample.OpenFileDialogSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="OpenFileDialogSample" Height="300" Width="300">
    <Window.DataContext>
        <ViewModel />
    </Window.DataContext>

    <Grid>
        <Button Name="ShowFilePickerButton" Click="ShowFilePicker_OnClick" Content="Open file" />
    </Grid>
</Window>

MainWindow.xaml.cs:

using System;
using System.IO;
using System.Windows;
using Microsoft.Win32;

namespace WpfOpenDialogExample
{
    public partial class OpenFileDialogSample : Window
    {
        public OpenFileDialogSample()
        {
            InitializeComponent();
        }

        private void ShowFilePicker_OnClick(object sender, RoutedEventArgs e)
        {
            var viewModel = this.DataContext as ViewModel;
            OpenFileDialog openFileDialog = new OpenFileDialog();
            if(openFileDialog.ShowDialog() == true && viewModel.OpenFileCommand.CanExecute(openFileDialog.FileName))
            {
               viewModel.OpenFileCommand.Execute(openFileDialog.FileName);
            }
        }

        private void ShowFolderPicker_OnClick(object sender, RoutedEventArgs e)
        {
            var viewModel = this.DataContext as ViewModel;
            FolderBrowserDialog openFolderDialog = new FolderBrowserDialog();
            if(openFolderDialog.ShowDialog() == DialogResul.Ok && viewModel.OpenFolderCommand.CanExecute(openFolderDialog.SelectedPath ))
            {
               viewModel.OpenFolderCommand.Execute(openFolderDialog.SelectedPath );
            }
        }
    }
}

ViewModel.cs:

public ICommand OpenFileCommand { get => new RelayCommand(OpenFile, CanOpenFile); }  

private void OpenFile(string filePath)
{
   ...
}

private bool CanOpenFile(string filePath)
{
   return File.Exists(filePath);
}

public ICommand OpenFolderCommand { get => new RelayCommand(OpenFolder, CanOpenFolder); }

private void OpenFolder(string folderPath)
{
   ...
}

private bool CanOpenFolder(string folderPath)
{
   return Directory.Exists(filePath);
}

RelayCommand.cs:

using System;
using System.Windows.Input;

namespace WpfOpenDialogExample
{
  /// <summary>
  /// An implementation independent ICommand implementation.
  /// Enables instant creation of an ICommand without implementing the ICommand interface for each command.
  /// The individual Execute() an CanExecute() members are suplied via delegates.
  /// <seealso cref="System.Windows.Input.ICommand"/>
  /// </summary>
  /// <remarks>The type of <c>RelaisCommand</c> actually is a <see cref="System.Windows.Input.ICommand"/></remarks>
    public class RelayCommand : ICommand
    {
      /// <summary>
      /// Default constructor to declare the concrete implementation of Execute(object):void and CanExecute(object) : bool
      /// </summary>
      /// <param name="executeDelegate">Delegate referencing the execution context method. 
      /// Delegate signature: delegate(object):void</param>
      /// <param name="canExecuteDelegate">Delegate referencing the canExecute context method.
      /// Delegate signature: delegate(object):bool</param>
      public RelayCommand(Action<object> executeDelegate , Predicate<object> canExecuteDelegate)
      {
        this.executeDelegate = executeDelegate;
        this.canExecuteDelegate = canExecuteDelegate;
      }

      /// <summary>
      /// Invokes the custom <c>canExecuteDelegate</c> which should check wether the command can be executed.
      /// </summary>
      /// <param name="parameter">Optional parameter of type <see cref="System.Object"/></param>
      /// <returns>Expected to return tue, when the preconditions meet the requirements and therefore the command stored in <c>executeDelegate</c> can execute.
      /// Expected to return fals when command execution is not possible.</returns>
      public bool CanExecute(object parameter)
      {
        if (this.canExecuteDelegate != null)
        {
          return this.canExecuteDelegate(parameter);
        }
        return false;
      }

      /// <summary>
      /// Invokes the custom <c>executeDelegate</c>, which references the command to execute.
      /// </summary>
      /// <param name="parameter">Optional parameter of type <see cref="System.Object"/></param>
      public void Execute(object parameter)
      {
        if (this.executeDelegate != null)
          this.executeDelegate(parameter);
      }

      /// <summary>
      /// The event is triggered every time the conditions regarding the command have changed. This occures when <c>InvalidateRequerySuggested()</c> gets explicitly or implicitly called.
      /// Triggering this event usually results in an invokation of <c>CanExecute(object):bool</c> to check if the occured change has made command execution possible.
      /// The <see cref="System.Windows.Input.CommandManager"/> holds a weakrefernce to the observer.
      /// </summary>
      public event EventHandler CanExecuteChanged
      {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
      }

      private readonly Action<object> executeDelegate;
      private readonly Predicate<object> canExecuteDelegate;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM