Viewmodel 在需要之前实例化

发布于 2024-12-11 23:52:50 字数 3941 浏览 0 评论 0原文

我对 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 上放置了一个断点,当我进入父视图时它会触发,但当我进入子视图时它应该触发(因此当打开数据网格中的工具提示)。有谁知道我该如何解决这个问题?

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

编辑:

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

我将工具提示更改为以下内容(根据 Rachels 帮助):

<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 在打开 ConsultantDashboard 时触发,而它应该在显示工具提示时打开。我可以在工具提示上放置某种事件/命令来触发 ViewModel 吗?另外,我认为标签的绑定有问题,因为它没有显示信息(尽管 ViewModel 没有传递正确的信息可能是同样的问题)。

再说一遍,如果您觉得它有点复杂,我很乐意进一步解释,或者根据要求提供更多代码。

已解决:

我找到了解决方案。我在 ChildView 的构造函数中指定绑定,而不是在其 XAML 或视图工具提示中指定。

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

I have a little problem with MVVM. Let me first sketch my problem.

I have a Parent View (DashboardConsultants) which has a datagrid. Each cell in that DataGrid has a tooltip, implemented like this:

 <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>

The tooltip calls up my ViewModel (AgreementDetailsViewModel), which has the following code:

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);
}

The goal of the ViewModel is to get an Agreement from the database (currently a static one...) and then pass it on to the child View (UC1001_AgreementDetails_View) to show as the tooltip. The child View has the following constructor so the controls can bind to the contract:

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

I put a breakpoint on the ViewModel Initialize, and it fires when I get on the parent View, but it should fire when I get on the child View (thus when opening the tooltip in the datagrid). Does anyone know how I can fix this?

More information/code can be provided if needed.

EDIT:

I tried some stuff and I now I got something like this (which I feel is a little closer to the solution).

I changed my tooltip to the following (according to Rachels help):

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

In my child view, I put the following binding

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

Now my AgreementDetailsViewModel, which has a property called AgreementDetailsContract with all the information I want to show, is the DataContext of my child view. But my problem still exist. The AgreementDetailsViewModels fires on opening the ConsultantDashboard, when it should open on displaying the tooltip. Is there some kind of event/command I can put on the tooltip to fire the ViewModel? Also, I think something is wrong with the Binding of my label because it doesn't show information (altough it could be the same problem that the ViewModel doesn't pass the right information).

Again, if it looks a little complex to you, I will be happy to explain it further, or give more code if asked.

SOLVED:

I got the solution. I specify the binding in the constructor of the ChildView instead of its XAML or in the View Tooltip.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

知足的幸福 2024-12-18 23:52:50

看起来您的 View 直接引用了 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;
}

It looks like your View is directly referencing the ViewModel, which means it will create a copy of your ViewModel when it starts up

This code

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

Should be

<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>

Your Data Structure should look something like this:

class MainViewModel
{
    ObservableCollection<AgreementViewModel> Agreements;
}

class AgreementViewModel
{ 
    // Loaded only when getter is called
    AgreementDetailViewModel AgreementDetails;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文