C# 从另一个ViewModel访问ViewModel中的方法
以前我有一个ViewModel,它变得非常大,所以我决定将它扩展到两个单独的ViewModel中。现在我想到了在ViewModels之间访问方法的问题。我需要运行例如UpdateDagRidView;它现在位于DataLogModel.cs中,每次在ViewModel.cs中的WinEventProc方法中更改窗口时,我都需要从ViewModel.cs运行它 正确的做法是什么?我试过:C# 从另一个ViewModel访问ViewModel中的方法,c#,wpf,mvvm,viewmodel,C#,Wpf,Mvvm,Viewmodel,以前我有一个ViewModel,它变得非常大,所以我决定将它扩展到两个单独的ViewModel中。现在我想到了在ViewModels之间访问方法的问题。我需要运行例如UpdateDagRidView;它现在位于DataLogModel.cs中,每次在ViewModel.cs中的WinEventProc方法中更改窗口时,我都需要从ViewModel.cs运行它 正确的做法是什么?我试过: var DL = new DataLogModel(); DL.UpdateDataGridView();
var DL = new DataLogModel();
DL.UpdateDataGridView();
无错误,但方法未被访问=DataGrid未更新。但是,从DataLogModel.cs访问相同的方法效果很好=DataGrid按预期更新
ViewModel.cs:
using Tracker.Models;
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
namespace Tracker
{
public class ChModel
{
private string DBconnectionString = ConfigurationManager.AppSettings["DBConnectionString"];
/// <summary>
/// We are interested to display only Today data in Chart
/// /// <summary>
public DataTable GetDataForChart()
{
DataTable ndt = new DataTable();
SqlConnection sqlcon = new SqlConnection(DBconnectionString);
...
return ndt;
}
}
class ViewModel : BaseViewModel
{
private GetActiveWindowTitle.WinEventDelegate dele = null;
long milliSeconds;
TimeSpan timeSpan;
DateTime CurrentDate;
public static string WindowTitle;
public static Stopwatch stopwatch = new Stopwatch();
public static Stopwatch ManualStopwatch = new Stopwatch();
public ViewModel()
{
// Let's start tracking windows
StartWindowTracking();
}
/// <summary>
/// Track windows
/// <summary>
private void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd,
int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
WindowTitle = GetActiveWindowTitle.GetActiveWindowTitleMethod();
if (!string.IsNullOrEmpty(WindowTitle))
{
stopwatch.Stop();
milliSeconds = stopwatch.ElapsedMilliseconds;
timeSpan = stopwatch.Elapsed;
CurrentDate = DateTime.Now;
MainProcess.AddRecordToDatatable(WindowTitle,
(int)(milliSeconds / 1000), DateTime.Now.Date, MainProcess.AdminHoursCode, MainProcess.userName);
UpdateDataGridView();
stopwatch.Start();
}
}
public void StartWindowTracking()
{
WindowTitle = GetActiveWindowTitle.GetActiveWindowTitleMethod();
dele = new GetActiveWindowTitle.WinEventDelegate(WinEventProc);
IntPtr m_hhook = GetActiveWindowTitle.SetWinEventHook(GetActiveWindowTitle.EVENT_OBJECT_FOCUS,
GetActiveWindowTitle.EVENT_OBJECT_FOCUS, IntPtr.Zero, dele, 0, 0, GetActiveWindowTitle.WINEVENT_OUTOFCONTEXT);
}
public string DBconnectionString { get; internal set; }
}
}
using Tracker.Models;
using System.Windows;
using System.Windows.Input;
namespace Tracker
{
class MainViewModel
{
public WindowViewModel WindowViewModel { get; set; }
public ViewModel ViewModel { get; set; }
public SettingsViewModel SettingsViewModel { get; set; }
public DataLogModel DataLogModel { get; set; }
}
}
这段代码的问题是DL是一个“新”的数据日志模型。。。它与DataGrid所在的DataLogModel实例不同,因此无法按您希望的方式刷新它
如果您试图在“正确”的DataLogModel上调用该方法,那么您需要的是对该DataLogModel的引用。例如,当您创建ViewModel和DataLogModel时,您会将DataLogModel的特定实例传递给ViewModel,通常在构造函数本身中才能调用它。您必须始终注意在正确的实例上操作:
var instanceA = new MyClass() { Value = 5 };
var instanceB = new MyClass() { Value = 5 };
// instanceA and instanceB are two different instances
// i.e. referencing two different memory addresses
ReferenceEquals(instanceA, instanceB); // false
// Does not modify the Value of instanceB
instanceA.Value = 10;
// instanceA.Value is 10 while instanceB.Value is still 5
instanceA.Value == instanceB.Value // false
将MainViewModel实例指定给视图的DataContext时,必须使用此实例,并且只能使用此实例及其聚合实例来修改视图
当前,您正在使用DataLogModel的两个实例,一个由视图引用,另一个断开连接:
// This instance is disconnected from the view.
// It is not the same instance that is referenced inside MainViewModel
var DL = new DataLogModel();
DL.UpdateDataGridView();
必须确保使用正确的引用正确初始化所有属性。如果ViewModel应该访问DataLogModel,则ViewModel需要聚合对此类型实例的共享引用:
ViewModel.cs
MainViewModel.cs
然后使用MainViewModel使用的相同共享DataLogModel实例正确初始化ViewModel:
谢谢你的回答!在我的例子中,有没有可能提供一些代码示例来运行这个特定的方法?或者任何示例的某个链接?管理多个视图模型的常用方法是使用一个具有公共属性的主视图模型,该属性包含对某些子视图模型的引用。@Clemens我添加了MainViewModel.cs。这就是你的意思吗?但是,DataLogModel.UpdateDagRidView也是不可能的`不知道您在MainViewModel中使用这些属性到底做了什么,但当然所有属性都应该初始化,即获取一个已签名的值。然后将MainViewModel的实例传递给视图的DataContext。在视图中,绑定到子视图模型属性,如{Binding DataLogModel.ActivityLogData}。
var instanceA = new MyClass() { Value = 5 };
var instanceB = new MyClass() { Value = 5 };
// instanceA and instanceB are two different instances
// i.e. referencing two different memory addresses
ReferenceEquals(instanceA, instanceB); // false
// Does not modify the Value of instanceB
instanceA.Value = 10;
// instanceA.Value is 10 while instanceB.Value is still 5
instanceA.Value == instanceB.Value // false
// This instance is disconnected from the view.
// It is not the same instance that is referenced inside MainViewModel
var DL = new DataLogModel();
DL.UpdateDataGridView();
class ViewModel : BaseViewModel
{
private DataLogModel DataLogModel { get; }
public ViewModel(DataLogModel dataLogModel)
{
// Aggregate an instance of DataLogModel.
// This enables the instantiating class to inject a *shared* instance.
this.DataLogModel = dataLogModel;
}
private void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd,
int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
...
this.DataLogModel.UpdateDataGridView();
...
}
}
class MainViewModel
{
private ViewModel ViewModel { get; }
private DataLogModel DataLogModel { get; }
public MainViewModel()
{
var sharedDataLogModelInstance = new DataLogModel();
this.DataLogModel = sharedDataLogModelInstance;
// Allow ViewModel to reference the same instance of DataLogModel
this.ViewModel = new ViewModel(sharedDataLogModelInstance);
}
}