视图模型在需要之前实例化

本文关键字:实例化 模型 视图 | 更新日期: 2023-09-27 18:12:26

我有一个小问题与MVVM。让我先简述一下我的问题。

我有一个父视图(DashboardConsultants),它有一个数据网格。DataGrid中的每个单元格都有一个工具提示,实现如下:

 <UserControl.Resources>
        <ResourceDictionary>
            <DataTemplate DataType="{x:Type vm:UC1001_AgreementDetailsViewModel}">
                <v:UC1001_AgreementDetails_View />
            </DataTemplate>    
        </ResourceDictionary>
 </UserControl.Resources>
<DataGridTextColumn.ElementStyle>
      <Style TargetType="{x:Type TextBlock}">
      <Setter Property="DataGridCell.ToolTip">
              <Setter.Value>
                   <vm:UC1001_AgreementDetailsViewModel />
              </Setter.Value>
      </Setter>

工具提示调用我的ViewModel (AgreementDetailsViewModel),它具有以下代码:

public UC1001_ActiveAgreementContract AgreementDetailsContract { get; set; }
public int AgreementID { get; set; }
public UC1001_AgreementDetailsViewModel()
{
    AgreementDetailsContract = new UC1001_ActiveAgreementContract();
    this.Initialize();
}
private void Initialize()
{
    GetRefData();
    ShowAgreementDetailsView();
}
private void GetRefData()
{
    UC1001_ActiveAgreementArguments args = new UC1001_ActiveAgreementArguments();
    args.AgreementID = 3;
    DefaultCacheProvider defaultCacheProvider = new DefaultCacheProvider();
    if (!defaultCacheProvider.IsSet("AgrDet:" + args.AgreementID))
    {
        ConsultantServiceClient client = new ConsultantServiceClient();
        AgreementDetailsContract = client.GetAgreementDetailsByAgreementID(args);
        defaultCacheProvider.Set("AgrDet:" + args.AgreementID, AgreementDetailsContract, 5);
    }
    else
    {
        AgreementDetailsContract = (UC1001_ActiveAgreementContract)defaultCacheProvider.Get("AgrDet:" + args.AgreementID);
    }
}

private void ShowAgreementDetailsView()
{
    // Initialize
    var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
    // Show content
    var agreementDetailsWorkspace = new Uri("UC1001_AgreementDetails_View", UriKind.Relative);
    regionManager.RequestNavigate("ContentRegion", agreementDetailsWorkspace);
}

ViewModel的目标是从数据库中获取协议(目前是静态的…),然后将其传递给子视图(UC1001_AgreementDetails_View)以显示为工具提示。子视图具有以下构造函数,因此控件可以绑定到契约:

public UC1001_AgreementDetails_View(ViewModels.UC1001_AgreementDetailsViewModel UC1001_AgreementDetailsViewModel)
    {            
        InitializeComponent();
        this.DataContext = UC1001_AgreementDetailsViewModel.AgreementDetailsContract;
    }

我在ViewModel Initialize上放置了一个断点,当我进入父视图时它会触发,但是当我进入子视图时它应该会触发(因此当在数据网格中打开工具提示时)。有人知道我该怎么解决这个问题吗?

如果需要,可以提供更多的信息/代码。

编辑:

我尝试了一些东西,我现在得到了这样的东西(我觉得这更接近解决方案)。

我改变了我的工具提示如下(根据rachel的帮助):

<Setter Property="DataGridCell.ToolTip">
          <Setter.Value>
                <v:UC1001_AgreementDetails_View DataContext="{Binding AgreementDetailsViewModel}" />
          </Setter.Value>
</Setter>

在子视图中,我放置了以下绑定

<Label Content="{Binding AgreementDetailsContract.Header}" Height="50" HorizontalAlignment="Left" Margin="8,6,0,0" Name="_labelHoofding" VerticalAlignment="Top" FontSize="22" />

现在我的AgreementDetailsViewModel,它有一个名为AgreementDetailsContract的属性,包含我想要显示的所有信息,是我的子视图的DataContext。但我的问题依然存在。当AgreementDetailsViewModels应该在显示工具提示时打开时,在打开顾问仪表板时触发。是否有某种事件/命令,我可以放在工具提示上,以触发ViewModel?此外,我认为我的标签的绑定是错误的,因为它不显示信息(尽管它可能是相同的问题,ViewModel不传递正确的信息)。

同样,如果它看起来有点复杂,我很乐意进一步解释它,或者如果被要求提供更多的代码。

解决:

我得到了答案。我在ChildView的构造函数中指定绑定,而不是在它的XAML或视图工具提示中。

public UC1001_AgreementDetails_View()
   {
      InitializeComponent();
      this.DataContext = new UC1001_AgreementDetailsViewModel();
   } 

视图模型在需要之前实例化

它看起来像你的视图直接引用ViewModel,这意味着它将创建你的ViewModel的副本,当它启动

这段代码

<Setter Property="DataGridCell.ToolTip">
    <Setter.Value>
        <vm:UC1001_AgreementDetailsViewModel />
    </Setter.Value>
</Setter>
应该

<Setter Property="DataGridCell.ToolTip">
    <Setter.Value>
        <!-- If you want to keep the DataTemplate, use a ContentControl -->
        <v:UC1001_AgreementDetails_View DataContext="{Binding AgreementDetails}" />
    </Setter.Value>
</Setter>

你的数据结构应该看起来像这样:

class MainViewModel
{
    ObservableCollection<AgreementViewModel> Agreements;
}
class AgreementViewModel
{ 
    // Loaded only when getter is called
    AgreementDetailViewModel AgreementDetails;
}