Jump between view and view model

2019-06-26 06:48发布

问题:

Is there a way to make Resharper or "just" Visual Studio (perhaps using a macro) jump between the view and the it's view model in the MVVM pattern.

Like Resharper can jump between the xaml and it's codebehind using F7 and Shift-F7

I follow the convention that the files are located like this

\Views\name\AbcView.xaml
\ViewModels\name\AbcViewModel.xaml

回答1:

Perhaps I should have googled first, here is a macro to do the same thing for .cpp and. .h files

I changed it a bit and assigned the macro to Ctrl+F7. Seems to work fine

Public Sub SwitchBetweenViewAndViewModel()
    '=====================================================================  
    ' If the currently open document is a view or viewmodel, attempts to  
    ' switch between them
    '=====================================================================  
    Dim currentDocument As String
    Dim targetDocument As String

    currentDocument = ActiveDocument.FullName

    If currentDocument.ToLower().Contains("\views\") And _
       (currentDocument.EndsWith("View.xaml", StringComparison.InvariantCultureIgnoreCase) Or _
        currentDocument.EndsWith("View.xaml.cs", StringComparison.InvariantCultureIgnoreCase)) Then
        targetDocument = currentDocument
        targetDocument = targetDocument.Replace(".xaml.cs", "")
        targetDocument = targetDocument.Replace(".xaml", "")
        targetDocument = targetDocument.Replace("\Views\", "\ViewModels\")
        targetDocument = targetDocument + "Model.cs"
    ElseIf currentDocument.ToLower().Contains("\viewmodels\") And currentDocument.EndsWith(".cs", StringComparison.InvariantCultureIgnoreCase) Then
        targetDocument = currentDocument
        targetDocument = targetDocument.Replace("\ViewModels\", "\Views\")
        targetDocument = targetDocument.Replace("ViewModel.cs", "View.xaml")
    End If

    If System.IO.File.Exists(targetDocument) Then
        OpenDocument(targetDocument)
    End If
End Sub

'=====================================================================  
' Given a document name, attempts to activate it if it is already open,  
' otherwise attempts to open it.  
'=====================================================================  
Private Sub OpenDocument(ByRef documentName As String)
    Dim document As EnvDTE.Document
    Dim activatedTarget As Boolean
    activatedTarget = False

    For Each document In Application.Documents
        If document.FullName = documentName And document.Windows.Count > 0 Then
            document.Activate()
            activatedTarget = True
            Exit For
        End If
    Next
    If Not activatedTarget Then
        Application.Documents.Open(documentName, "Text")
    End If
End Sub


回答2:

What if more than one ViewModels are releated to the same View? :)

U may simply use DesignInstance markup extension to get R# navigation and code completion in binding work well:

namespace WpfApplication1.ViewModels
{
  public class PersonViewModel
  {
    public string Name { get; set; }
    public int Age     { get; set; }
  }
}

And the corresponding view:

<Window x:Class="WpfApplication1.Views.PersonView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="PersonInfo" Height="300" Width="300"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        mc:Ignorable="d"

        xmlns:vms="clr-namespace:WpfApplication1.ViewModels"

        d:DataContext="{d:DesignInstance Type=vms:PersonViewModel}">

  <UniformGrid>
    <TextBlock Grid.Row="0" Grid.Column="0" Text="Name" />
    <TextBlock Grid.Row="0" Grid.Column="1" Text="Age" />
    <TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding Name}" />
    <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Age}" />
  </UniformGrid>

</Window>

Now R# can verify all the references to ViewModel properties in bindings, help you to complete property names and also can navigate directly to this properties. Moreover, all the code above is quickly baked using the R# Specify DataContext type in ... quick fix (at unresolved binding expressions).

p.s. View still have no dependency on ViewModel because all design-time attributes will be removed after compilation (by mc:Ignorable="d" attribute).



回答3:

Using @Karstens answer I changed the sub that switches in between files to both being able to switch in between .cpp and .h files, as well as View and View Model files.

If you want to do the same, follow the instructions in his link but use this sub instead:

'=====================================================================  
' If the currently open document is a CPP or an H file, attempts to  
' switch between the CPP and the H file.  
'
' If the currently open document is a View.xml or an ViewModel.cs file, attempts to  
' switch between the View and the ViewModel file.  
'=====================================================================  
Sub SwitchBetweenAssociatedFiles()
    Dim currentDocument As String
    Dim targetDocument As String

    currentDocument = ActiveDocument.FullName

    If currentDocument.EndsWith(".cpp", StringComparison.InvariantCultureIgnoreCase) Then
        targetDocument = Left(currentDocument, Len(currentDocument) - 3) + "h"
    ElseIf currentDocument.EndsWith(".h", StringComparison.InvariantCultureIgnoreCase) Then
        targetDocument = Left(currentDocument, Len(currentDocument) - 1) + "cpp"
    ElseIf currentDocument.EndsWith("View.xaml", StringComparison.InvariantCultureIgnoreCase) Then
        targetDocument = currentDocument.Replace("\Views\", "\ViewModels\")
        targetDocument = targetDocument.Replace("\View\", "\ViewModel\")
        targetDocument = targetDocument.Replace("View.xaml", "ViewModel.cs")
    ElseIf currentDocument.EndsWith("ViewModel.cs", StringComparison.InvariantCultureIgnoreCase) Then
        targetDocument = currentDocument.Replace("\ViewModels\", "\Views\")
        targetDocument = targetDocument.Replace("\ViewModel\", "\View\")
        targetDocument = targetDocument.Replace("ViewModel.cs", "View.xaml")
    End If

    If System.IO.File.Exists(targetDocument) Then
        OpenDocument(targetDocument)
    End If

End Sub

I assigned it to Alt + § which was free in my configuration. Handy next to Alt + Tab. ^_^