简体   繁体   English

在C#中使用MVVM(Model-View-ViewModel)的WPF OpenFileDialog

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

How to write WPF OpenFileDialog using MVVM (Model-View-ViewModel) in c#? 如何在C#中使用MVVM(Model-View-ViewModel)编写WPF OpenFileDialog? I have visited some websites regarding this OpenFileDialog ,but I didn't get clear idea about it. 我已经访问了一些有关此OpenFileDialog的网站,但是我对此不清楚。 This is my code 这是我的代码

In View.xaml : 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 : 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 : 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. 我应该如何编写代码以获取OpenFileDialog。 I have seen this link WPF OpenFileDialog with the MVVM pattern? 我已经看到了带有MVVM模式的WPF OpenFileDialog链接吗? but I don't know how to write it for my above code. 但是我不知道如何为上面的代码编写它。 please someone help me by editing my code to get OpenFileDailog. 请有人通过编辑我的代码来获取OpenFileDailog来帮助我。

In my opinion this kind of things doesn't belong in to the ViewModel. 我认为这种事情不属于ViewModel。 It's View specific logic. 这是查看特定的逻辑。 The View alone handles user input and then sends it to the ViewModel. View独自处理用户输入,然后将其发送到ViewModel。 ViewModel never asks the View to do something. ViewModel从不要求View做某事。 This would invert the dependency chain and couple the ViewModel to the View. 这将反转依赖关系链,并将ViewModel耦合到View。 The dependencies have to be like this: View --> ViewModel --> Model. 依赖关系必须是这样的:View-> ViewModel-> Model。 The ViewModel doesn't even know about the type of views nor that there is a View at all. ViewModel甚至不知道视图的类型,也不知道有一个View。

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. 为此,您可以在代码背后创建一个简单的事件处理程序,并将其附加到按钮的click事件上。 You take the picked file and use an ICommand to invoke eg an open file action. 您获取选取的文件,然后使用ICommand调用例如打开文件的操作。 That's MVVM (or MVP). 那就是MVVM(或MVP)。 Separate the concerns of the views from your models. 将视图的关注点与模型分开。

MainWindow.xaml: 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: 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: 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: 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;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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