C# viewmodel变量更改时在其他窗口中调用方法
我有一个名为C# viewmodel变量更改时在其他窗口中调用方法,c#,wpf,C#,Wpf,我有一个名为Timeline(不是我的主窗口)的窗口,可以打开多次,并传递不同的值。我想做的是,当主窗口的viewmodel中的某个值发生更改时,我想在每个打开的时间线窗口中调用一个方法 这是一个不断变化的变量。当它发生变化时,我想调用testDraw()函数(也在viewmodel中) 以下是时间轴窗口背后的代码: public partial class Timeline : Window { public List<double> xValues; public
Timeline
(不是我的主窗口)的窗口,可以打开多次,并传递不同的值。我想做的是,当主窗口的viewmodel中的某个值发生更改时,我想在每个打开的时间线窗口中调用一个方法
这是一个不断变化的变量。当它发生变化时,我想调用testDraw()函数(也在viewmodel中)
以下是时间轴窗口背后的代码:
public partial class Timeline : Window
{
public List<double> xValues;
public List<double> yValues;
public double currentX;
public double currentY;
public Timeline(List<double> x, List<double> y)
{
InitializeComponent();
xValues = x;
yValues = y;
}
public void setCurrentValues(int i)
{
currentX = xValues[i];
currentY = yValues[i];
}
}
公共部分类时间线:窗口
{
公共价值清单;
公共价值清单;
公共双电流x;
公共双电流;
公共时间线(列表x、列表y)
{
初始化组件();
xvalue=x;
y值=y;
}
公共无效setCurrentValues(int i)
{
电流x=x值[i];
当前y=y值[i];
}
}
函数“testDraw()”应该在当前打开的时间轴窗口中循环,并调用这些窗口中的两个函数
我得到的错误是:
调用线程无法访问此对象,因为另一个线程拥有它。
-因此我尝试在方法中使用Dispatcher.Invoke
,但该方法也不起作用
注意:我不确定如何将此位保留为MVVM格式。您是否考虑过使用EventAggregator在windows之间进行通信?用户界面线程上有一个subscribign选项:
构造每个时间线对象时,请订阅
eventAggregator.GetEvent<IterationChangeEvent>().Subscribe(UpdateUI, ThreadOption.UIThread);
private void UpdateUI(Iteration iteration)
{
this.setCurrentValues(iteration);
this.linechart1.HighlightPoint(this.currentX, this.currentY);
}
eventAggregator.GetEvent().Subscribe(UpdateUI,ThreadOption.UIThread);
私有void UpdateUI(迭代)
{
此.setCurrentValue(迭代);
this.linechart1.HighlightPoint(this.currentX,this.currentY);
}
当CurrentIteration更改调用时,在主窗口中:
eventAggregator.GetEvent<IterationChangeEvent>().Publish(this.currentIteration);
eventAggregator.GetEvent().Publish(this.currentIteration);
您的事件类将出现以下情况:
public class IterationChangeEvent : CompositeWpfEvent<int>
{
}
公共类迭代更改事件:CompositeWpfEvent
{
}
您必须在调度程序中调用整个testDraw
方法,因为即使是应用程序.Current.Windows
的getter也需要它:
public void testDraw()
{
Application.Current.Dispatcher.Invoke(new Action(() =>
{
foreach (Timeline timeLineWin in Application.Current.Windows)
{
timeLineWin.setCurrentValues(CurrentIteration);
timeLineWin.linechart1
.HighlightPoint(timeLineWin.currentX, timeLineWin.currentY);
}
}));
}
您能否发布您的无效操作异常的StackTrace
?应该很容易找到罪魁祸首。StackTrace:“在System.Windows.Threading.Dispatcher.VerifyAccess()\r\n在System.Windows.Threading.DispatcherObject.VerifyAccess()\r\n在System.Windows.Application.get\u Windows()”stringUpdate我的'TestDraw'函数以显示我试图使用的调度程序。我当然可能是错的,但我认为.Subscribe(UpdateUI)
应该是。Subscribe(UpdateUI,ThreadOption.UIThread)
避免OP的无效操作异常
,因为默认值只是ThreadOption。PublisherThread
如文档所示。也可能每个窗口都有自己的dispatcher,这意味着您必须手动调用正确dispatcher中的操作。(当然,整个过程都应该使用MVVM来完成。)谢谢,@haindl我已经更新了代码并添加了一个引用。EventAggregator是MVVM使用的常见模式,因此您的代码仍然是MVVM。你不需要在虚拟机中循环,这就是重点。您只需发布单个事件。您设置的每个订阅服务器都将收到事件。@openshac即使您使用事件聚合器
,更新订阅中的基础视图模型(控件是数据绑定的)而不是直接更新linechart1
控件肯定是一个更好的解决方案。(至少如果您希望以MVVM的方式执行此操作。)是的,很遗憾,原始OP没有时间线VM,时间线类是一个窗口。出现此错误-“无法将lambda表达式转换为类型“System.Delegate”,因为它不是委托类型”。委托方法在调用中是什么?Action?@pfinfernoDispatcher.Invoke()
在.net 4.5中进行了扩展,不仅支持委托
,还支持操作
参数。我编辑了我的答案以反映这一点,因此如果您使用的是4.5之前的.net framework,它会编译。啊,是的,我使用的是4.0。标记你的答案。我现在有一个残疾例外,也许你能帮忙?它在foreach循环中突出显示timeLineWin
,表示无法将Project1.main窗口
转换为Project1.Timeline
。知道为什么吗?如果我使用foreach(Timeserver.Timeline timeLineWin in Application.Current.Windows)
@pfferno,我也会得到同样的结果。如果你有其他类型的窗口,你可以使用LINQ:Application.Current.Windows.OfType()过滤它们。除此之外——不客气,很高兴我能帮助你!:-)
public void testDraw()
{
Application.Current.Dispatcher.Invoke(new Action(() =>
{
foreach (Timeline timeLineWin in Application.Current.Windows)
{
timeLineWin.setCurrentValues(CurrentIteration);
timeLineWin.linechart1
.HighlightPoint(timeLineWin.currentX, timeLineWin.currentY);
}
}));
}