4

I have an "open" command where the user can chose a file. When the file is chosen (and therefore I have got the filepath as a string) I get a new instance of my DataView (with the NonShared and CreationPolicy attributes) out of the CompositionContainer and display it in a specific region. My DataView gets its DataViewModel via DI. Now my problem is how do I pass the selected filepath to the NEW (created after file is chosen) ViewModel?

My first approach seemed clever and worked as long as I only created one View. But since I create multiple views (Tabs) the following approach does NOT work because I cant compose the same value more than once.

if (fileDialog.ShowDialog() == true)
{               
    Container.ComposeExportedValue("FilePath", fileDialog.FileName);
    IRegion contentRegion = regionManager.Regions[Regions.CONTENT];
    contentRegion.Add(Container.GetExportedValue<IDataView>(), null, true);
} 

[ImportingConstructor]
public DataViewModel(IRegionManager regionManager, 
    [Import("FilePath")] string filePath)
{ }

Is there any other way to inject / pass my string parameter to the viewmodel?

Sebastian
  • 316
  • 1
  • 3
  • 12

2 Answers2

1

I think you need to use a service for opening files rather than exporting values through MEF.

If you had a common service that all your ViewModels used, they could simply import your service and call an OpenFile() method.

I have an MVVM open source project, that has a quick example of doing this. See the templates example here.

Also check the top answer here, they have another implementation.

Community
  • 1
  • 1
jonathanpeppers
  • 26,115
  • 21
  • 99
  • 182
  • Thats what I also thought about, but then I came to the problem that the View and the ViewModel do not exist when the user choses a file. They are created when the user has successfully chosen a file. A solution would be to create the View and its ViewModel when the user clicks "open" and if he cancels the filedialog, destroy the View and ViewModel, but that sounds awkward. – Sebastian Aug 28 '11 at 07:16
  • If you are truly following MVVM, then you will have an appropriate View and ViewModel for each screen (or section) in your application. If the opening of a file displays a new window after choosing the file, then this work would be done in a "parent" ViewModel and you would not need to create (or import with MEF) this "child" ViewModel until the file is chosen. – jonathanpeppers Aug 28 '11 at 18:53
  • The work is actually done in the "parent" viewmodel, but the data that must be displayed (related on the chosen file) must be displayed in a new view, and either way i need to pass a) the information of the file or b) the data that is generated due to the chosen file to the new view, otherwise the view does not know what to display (to get a better understanding maybe watch how the open file process in f.e. Notepadd++ is done. You press Open, you choose a file, then press ok, and then a new tab with the file data is displayed (The tab is the view i want to create). – Sebastian Aug 29 '11 at 15:16
  • Your new tab just needs to expose a string property that the parent ViewModel would set with the file name. – jonathanpeppers Aug 29 '11 at 16:01
  • Injecting a dependency through a Views Datacontext (thats what I must do since my View creates the ViewModel -> View.DataContext.MyStringProperty = myString;) sounds awkward. When I have found a "clean" solution, I will edit my question with the solution. But thanks anyway – Sebastian Aug 29 '11 at 18:48
  • You would not do this from your View. There should be no C# code in your view at all. This would all be done from your parent ViewModel. I think there is a language barrier here. – jonathanpeppers Aug 29 '11 at 23:57
  • I think its not a language barrier, but more a problem describing barrier. In short: I have a string and a view which holds a viewmodel in its datacontext, and want to get this string in this viewmodel. thats it – Sebastian Sep 01 '11 at 17:24
  • I don't think you need a string in your View at all--this should be in your ViewModel. Proper MVVM views should have Xaml markup and that's it. – jonathanpeppers Sep 01 '11 at 17:32
  • I do want this string in my viewmodel (as mentioned above). my view does not have any code behind (except the viewmodel import). The point is I use the MVVM pattern with "View first" approach (see prism doc) that why i dont have access to my viewmodel directly. – Sebastian Sep 02 '11 at 05:45
  • I still don't think you should have anything in your View. Here is the proper way to open a file dialog: http://nomvvm.codeplex.com/SourceControl/changeset/view/83031#1639419 – jonathanpeppers Sep 02 '11 at 11:46
  • View First or ViewModel First is another debate with many pros and cons i think. But your OpenFile method is the same as mine in the original question: And again my problem: how do you get the path parameter to a new viewmodel which you create (get from the DI Container) after the filedialog was successfully opened and the path variable is filled? MEF does not support passing parameters (unity does i think). – Sebastian Sep 02 '11 at 16:15
  • Did you see the code from that link? The file path is supplied in an `out` parameter. – jonathanpeppers Sep 02 '11 at 22:47
  • Maybe I'm just describing my problem wrong. I dont want the string in the ViewModel where the parameter is defined, i want it in a NEW VIEWMODEL which i create after the file is chosen. But i think its impossible to break this communication barrier without a sample implementation, so i will provide one within the next days – Sebastian Sep 03 '11 at 07:51
1

I always handled this kind of thing within a ViewModel

My ParentViewModel would contain an instance of the OpenFileViewModel, and when the ParentViewModel.SelectFileCommand gets executed, it calls something like OpenFileViewModel.SelectFile()

To get the selected file, I often subscribe to OpenFileViewModel.PropertyChanged and listen for change events on the FileName property, or sometimes I'll have an overwritable ProcessFile method which I can hook up an event to that will fire when a file gets selected.

The OpenFileViewModel.SelectFilemethod usually looks something like this

private void SelectFile()
{
    var dlg = new OpenFileDialog();
    dlg.DefaultExt = this.Extension;
    dlg.Filter = this.Filter;

    if (dlg.ShowDialog() == true)
    {
        var file = new FileInfo(dlg.FileName);
        FileName = file.FullName;

        if (ProcessFileDelegate != null)
            ProcessFileDelegate()
    }
}

and my ParentViewModel will often contain code that looks something like this:

public ParentViewModel()
{
    this.OpenFileDialog = new OpenFileViewModel();
    this.OpenFileDialog.PropertyChanged += OpenFileDialog_PropertyChanged;
    this.OpenFileDialog.ProcessFileDelegate = ProcessFile;
}
Rachel
  • 130,264
  • 66
  • 304
  • 490