【问题标题】:Multiple instances of a ViewmodelViewmodel 的多个实例
【发布时间】:2011-03-21 15:40:45
【问题描述】:

我对 WPF 和 MVVM 非常陌生(这是我在 WPF 中的第一个项目)。我正在处理的项目应该接受一些搜索条件,并在网格中显示结果。为了构造查询,我使用了动态 LINQ 查询。我似乎在管理我的 ProjectSearchViewModel 实例时遇到问题,该实例对应于负责收集搜索条件和执行查询的视图。创建 MainWindowViewModel 时会创建一个实例。这将创建所有其他视图模型实例。这是我所期望的。但是当显示 MainWindow 时,我得到了另一个 ProjectSearchViewModel,我猜是从绑定中获得的。

大致思路是这样的:

  1. 在ProjectSearchView中填写搜索条件。

  2. 按下加载命令时,我使用响应式扩展方法发送 SearchResultMessage。

  3. 消息被 MainWindowViewModel 拾取

  4. MainWindowViewModel 正在查询 ProjectSearchViewModel.SearchResult 并将 IObservable 列表分配给 AllProjectsViewModel.AllProjects,该列表绑定到数据网格以显示结果(AllProjectView 负责显示带有结果项目列表的网格)

问题是 SearchResultMessage 的参数填充和发送发生在 ProjectSearchViewModel 的一个实例中,而从 MainWindowViewModel 实际查询 SearchResult 发生在另一个实例中,其中所有搜索条件均为空。

我想我别无选择,只能发布我的代码:这里是它的精简版,省略了一些 iDisposable 管道等。对于我的模型,我使用 Entity Framework 4。

正如我所提到的,我是一个完全的新手,所以如果有人看到任何公然无视常识的行为,请直言不讳。



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

结束类

【问题讨论】:

  • 第 5 个代码块, 行,这段代码很可疑,我会删除它。尝试这样做并说出之后发生的事情。

标签: wpf mvvm


【解决方案1】:

每次您创建 ProjectSearchView 用户控件时,您也会创建一个 ProjectSearchViewModel。您应该从您的 usercontrl xaml 中删除以下内容。

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

因为你的datatemplate你不需要为ProjectSearchView设置datacontext,它已经有了正确的datacontext。

【讨论】:

  • 原来如此。谢谢。
猜你喜欢
  • 2022-12-14
  • 1970-01-01
  • 1970-01-01
  • 2011-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-19
  • 2013-06-30
相关资源
最近更新 更多