Reputation: 1945
I have a window called Timeline
(not my mainwindow), that can be opened several times with different values being passed. What I'm trying to do is, when a certain value is changed in my viewmodel for my main window, I want to call a method in each Timeline
window that is open.
Here's the variable that is constantly changing. When it does change, I want to call the testDraw() function (also in the viewmodel).
private int _currentIteration;
public int CurrentIteration //used to hold current index of the list of data fields
{
get { return _currentIteration; }
set
{
_currentIteration = value;
this.OnPropertyChanged("CurrentIteration");
}
}
//Want to call this when CurrentIteration changes
public void testDraw()
{
foreach (Timeline timeLineWin in Application.Current.Windows)
{
Application.Current.Dispatcher.Invoke(new Action(() =>
{
timeLineWin.setCurrentValues(CurrentIteration);
timeLineWin.linechart1.HighlightPoint(timeLineWin.currentX, timeLineWin.currentY);
}));
//linechart1 is a winforms component on the timeline window
}
}
Here's the code behind for the timeline window:
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];
}
}
The function 'testDraw()' is supposed to loop through all the currently open Timeline
windows and call the two functions in those windows.
The error I got was:
The calling thread cannot access this object because a different thread owns it.
- So I tried using Dispatcher.Invoke
in the method which also did not work.
Note: I wasn't sure how to keep this bit in the MVVM format.
Upvotes: 1
Views: 79
Reputation: 3221
You have to invoke your whole testDraw
method in the Dispatcher
because even the getter of Application.Current.Windows
requires it:
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);
}
}));
}
Upvotes: 1
Reputation: 5165
Have you thought about using the EventAggregator for communicating between windows? There is an option for subscribign on the user interface thread: https://msdn.microsoft.com/en-us/library/ff921122.aspx
When you construct each time line object subscribe to the
eventAggregator.GetEvent<IterationChangeEvent>().Subscribe(UpdateUI, ThreadOption.UIThread);
private void UpdateUI(Iteration iteration)
{
this.setCurrentValues(iteration);
this.linechart1.HighlightPoint(this.currentX, this.currentY);
}
In your main window when the CurrentIteration changes call:
eventAggregator.GetEvent<IterationChangeEvent>().Publish(this.currentIteration);
Your event class would lool something like this:
public class IterationChangeEvent : CompositeWpfEvent<int>
{
}
Upvotes: 1