Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/271.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# viewmodel变量更改时在其他窗口中调用方法_C#_Wpf - Fatal编程技术网

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?@pfinferno
Dispatcher.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);
        }
    }));
}