开发者

Multiple instances of a Viewmodel

Im very new to the WPF and MVVM (this is my 1st project in WPF). The project I'm working on is supposed to accept some search criteria, and display the results in the grid. To construct the query I'm using Dynamic LINQ queries. I seem to have issues managing instances of my ProjectSearchViewModel which corresponds to the view that's responsible for collecting the search criteria and executing the query. One instance is created when I create MainWindowViewModel. This creates all other viewmodel instances. This is what I expect. But when time comes to Show the MainWindow, I get another ProjectSearchViewModel, I guess from the binding.

The general idea is this:

  1. The search criteria are filled in the ProjectSearchView.

  2. When Load Command is pressed, I send SearchResultMessage using Reactive Extensions method.

  3. The message is picked up by MainWindowViewModel

  4. MainWindowViewModel is querying the ProjectSearchViewModel.SearchResult and assigning the IObservable List to AllProjectsViewModel.AllProjects which is bound to a datagrid to show the results (AllProjectView is responsible to show the grid with resulting projects list)

The problem is that the parameter filling and sending of the SearchResultMessage happens in one instance of ProjectSearchViewModel and the actual querying of SearchResult from MainWindowViewModel happens in another instance, where all the search criteria are empty.

I guess I have no choice but to post my code: Here it the abridged version of it, omitting some iDisposable plumbing and such. For my model I use Entity Framework 4.

As I mentioned, I'm a total newbie so If anyone sees any blatant disregard for common sense, please set me straight.

Imports Cheminator.ViewModel

Partial Public Class App

    Inherits Application


    Private viewModel As MainWindowViewModel

    Private window As MainWindow

    Protected Overrides Sub OnStartup(ByVal e As StartupEventArgs)

        MyBase.OnStartup(e)

        window = New MainWindow

        viewModel = New MainWindowViewModel '1st instance of ProjectSearchViewModel created Here

        window.DataContext = viewModel

        window.Show() '2nd instance of ProjectSearchViewModel created Here

    End Sub

End Class

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Cheminator"
    xmlns:vm="clr-namespace:Cheminator.ViewModel"
    xmlns:vw="clr-namespace:Cheminator.Views"
    xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:dxd="http://schemas.devexpress.com/winfx/2008/xaml/docking"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
xmlns:dxnb="http://schemas.devexpress.com/winfx/2008/xaml/navbar"
xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib"
    Title="DXWpfApplication" Height="600" Width="800"
    dx:ThemeManager.ThemeName="Office2007Blue"
>

<Window.Resources>
    <ResourceDictionary Source="MainWindowResources.xaml" />
</Window.Resources>

<dxd:DockLayoutManager>
    <dxd:LayoutGroup>
        <dxd:LayoutGroup Orientation="Vertical"  Width="3*">
            <dxd:DocumentGroup Height="3*" SelectedTabIndex="0">
                <dxd:DocumentPanel Caption="Document1" Height="3*" >
             开发者_开发百科        <ContentControl
                      Content="{Binding Path=ProjectsVM}"
                      />
                </dxd:DocumentPanel>
            </dxd:DocumentGroup>
            <dxd:LayoutPanel Caption="Search Criteria" Height="*"  CaptionImage="Images/Icons/DetailView.png">                  

                <ContentControl
                      Content="{Binding Path=ProjectsSearchVM}"
                      />
            </dxd:LayoutPanel>
        </dxd:LayoutGroup>
    </dxd:LayoutGroup>
</dxd:DockLayoutManager>

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Cheminator"
xmlns:vm="clr-namespace:Cheminator.ViewModel"
xmlns:vw="clr-namespace:Cheminator.Views"    >

<DataTemplate DataType="{x:Type vm:AllProjectsViewModel}">
    <vw:AllProjectsView />
</DataTemplate>

<DataTemplate DataType="{x:Type vm:ProjectSearchViewModel}">
    <vw:ProjectSearchView />
</DataTemplate>

<UserControl x:Class="Cheminator.Views.AllProjectsView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
         xmlns:dxd="http://schemas.devexpress.com/winfx/2008/xaml/docking"
         xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
         xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"       
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:vm="clr-namespace:Cheminator.ViewModel"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">

    <dxg:GridControl AutoPopulateColumns="True" ShowBorder="False" >
        <dxg:GridControl.DataSource>
            <Binding Path="AllProjects"/>                     
        </dxg:GridControl.DataSource>
        <dxg:GridControl.View>
            <dxg:TableView>

        </dxg:TableView>
        </dxg:GridControl.View>
   </dxg:GridControl>
</UserControl>

<UserControl x:Class="Cheminator.Views.ProjectSearchView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:vm="clr-namespace:Cheminator.ViewModel"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="160" d:DesignWidth="470">
<Grid Height="160" Width="470">
    <Grid.DataContext>
        <vm:ProjectSearchViewModel />
    </Grid.DataContext>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="175*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Label Content="Cotation ID:" Height="28" Margin="49,12,32,0" Name="Label1" VerticalAlignment="Top" />
    <TextBox Grid.Column="1" Height="23" Margin="0,14,159,0" Name="CotationIDTextBox" VerticalAlignment="Top" Text="{Binding Path=CotationID, UpdateSourceTrigger=LostFocus}"/>

    <Label Grid.Row="1" Content="Cotation Name:" Height="28" Margin="49,6,6,0" Name="Label2" VerticalAlignment="Top" />
    <TextBox Grid.Row="1" Grid.Column="1" Height="23" Margin="0,8,159,0" Name="CotationNameTextBox" VerticalAlignment="Top" Text="{Binding Path=ProjectSummary, UpdateSourceTrigger=PropertyChanged}"/>

        <Label Grid.Row="2" Content="User:" Height="28" Margin="49,6,32,0" Name="Label3" VerticalAlignment="Top" />
    <TextBox Grid.Row="2" Grid.Column="1" Height="23" Margin="0,8,159,0" Name="UserTextBox" VerticalAlignment="Top" Text="{Binding Path=UserName, UpdateSourceTrigger=PropertyChanged}"/>
    <Button 
                    Command="{Binding Path=LoadCommand}"
                    Content="_Load"
                    HorizontalAlignment="Right"
                    Margin="0,10,51,12" 
                    MinWidth="60" Grid.Row="3" Width="72" Grid.Column="1" />
</Grid>
</UserControl>

Public Class MainWindowViewModel
    Inherits ViewModelBase

    Private _commands As ReadOnlyCollection(Of CommandViewModel)
    Private _ProjectsVM As AllProjectsViewModel
    Private _ProjectsSearchVM As ProjectSearchViewModel

    Public Sub New()
        MyBase.DisplayName = "Cheminator"
        _ProjectsSearchVM = New ProjectSearchViewModel

        Messenger.[Default].OfType(Of SearchResultMessage) _
            .Subscribe(Sub(param As SearchResultMessage)
                           ProjectsVM.AllProjects = ProjectsSearchVM.SearchResult
                       End Sub)
        _ProjectsVM = New AllProjectsViewModel
    End Sub

    Public ReadOnly Property ProjectsVM As AllProjectsViewModel
        Get

            If (_ProjectsVM IsNot Nothing) Then
                Return _ProjectsVM
            End If
            Return Nothing
        End Get
    End Property


    Public ReadOnly Property ProjectsSearchVM As ProjectSearchViewModel
        Get

            If (_ProjectsSearchVM IsNot Nothing) Then
                Return _ProjectsSearchVM
            End If
            Return Nothing
        End Get
    End Property

End Class

Public Class AllProjectsViewModel
    Inherits ViewModelBase


    Private m_ProjectsList As ObservableCollection(Of xGMV_Cotation)


    Public Sub New()
        MyBase.DisplayName = "Temp AllProjectsViewModel Name" 'Strings.AllProjectsViewModel_DisplayName

    End Sub


    Public Property AllProjects() As ObservableCollection(Of xGMV_Cotation)
        Get
            Return m_ProjectsList
        End Get
        Set(ByVal value As ObservableCollection(Of xGMV_Cotation))
            m_ProjectsList = value
            OnPropertyChanged("AllProjects")
        End Set
    End Property

End Class

Public Class ProjectSearchViewModel
    Inherits ViewModelBase


    Private m_ProjectsList As ObservableCollection(Of xGMV_Cotation)

    Public Sub New()
        MyBase.DisplayName = "Cheminator.ProjectSearchViewModel"




    End Sub

    Dim _CotationID As Integer
    Public Property CotationID As Integer
        Get
            Return _CotationID
        End Get
        Set(ByVal value As Integer)
            _CotationID = value
            MyBase.OnPropertyChanged("CotationID")
        End Set
    End Property
    Public Property ProjectSummary As String
    Public Property UserName As String


    Private m_LoadCommand As RelayCommand
    Public ReadOnly Property LoadCommand As ICommand
        Get
            If m_LoadCommand Is Nothing Then
                Dim LoadAction As New Action(Of Object)(AddressOf Me.Load)
                m_LoadCommand = New RelayCommand(LoadAction)
            End If


            Return m_LoadCommand
        End Get
    End Property

    Public ReadOnly Property SearchResult() As ObservableCollection(Of xGMV_Cotation)
        Get

            Dim xWhere As String = ""
            Dim i As Integer = 0
            Dim parameterList As New ArrayList
            If Not String.IsNullOrEmpty(CotationID) Then
                xWhere = String.Format("CotationID = @{0}", i)
                parameterList.Add(CotationID)
                i += 1
            End If

            If Not String.IsNullOrEmpty(ProjectSummary) Then
                If i > 0 Then
                    xWhere = xWhere & " AND "
                End If
                xWhere = xWhere & String.Format("ProjectSummary = '@{0}'", i)
                i += 1
                parameterList.Add(ProjectSummary)
            End If

            If Not String.IsNullOrEmpty(UserName) Then
                If i > 0 Then
                    xWhere = xWhere & " AND "
                End If
                xWhere = xWhere & String.Format("UserName = '@{0}'", i)
                i += 1
                parameterList.Add(UserName)
            End If


            Return New ObservableCollection(Of xGMV_Cotation)(DataContext.DBEntities.xGMV_Cotations.Where(xWhere, parameterList.ToArray))
        End Get

    End Property

    Private Sub Load()


        OnPropertyChanged("SearchResult")
        Messenger.Default.Send(New SearchResultMessage())

    End Sub

End Class


everytime you create a ProjectSearchView usercontrol, you also create a ProjectSearchViewModel too. you should remove the following from your usercontrl xaml.

<Grid.DataContext>
    <vm:ProjectSearchViewModel />
</Grid.DataContext>

because of your datatemplate you do not need to set the datacontext for ProjectSearchView, it already has the right datacontext.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜