I'm hoping someone can help, as I'm a bit stuck. I have a strategy that I want to change the colour of its tab in the chart window. It works, but only if I enable the strategy directly from the chart. If I enable the strategy from the Control Centre then I get the following error:
"The calling thread cannot access this object because a different thread owns it"
I can add the strategy from the chart (by clicking the strategy button) without enabling it, and it appears in Control Centre as you would expect. But if I then tick the box in control centre to enable it, I get the error. But, if I bring up the strategy window from the chart and enable it that way instead, it works fine.
Also, after the error has occurred, if I just refresh the chart (by pressing F5) then it works fine. But, disabling and re-enabling from Control Centre creates the error. I've tried to strip down the code as much as possible to isolate the issue, and copied below (also attached). Also note that I only see the error in Visual Studio; it doesn't appear in the output or log (but the tab won't change colour as a result).
I suspect that I need to somehow call the dispatcher from a different thread (whatever Control Centre is using perhaps), but the dispatcher and thread name are saying it's correct...
I'm so close to this working! Any ideas?
public class TabTest4 : Strategy
{
private Style redstyle;
private Style defaultstyle;
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Name = "TabTest4";
Calculate = Calculate.OnEachTick;
}
else if (State == State.Configure)
{
string customResources = @"
<ResourceDictionary xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
<Style TargetType=""{x:Type TabItem}"" x:Key=""RedStyle"">
<Setter Property=""BorderThickness"" Value=""0""/>
<Setter Property=""Padding"" Value=""0"" />
<Setter Property=""HeaderTemplate"">
<Setter.Value>
<DataTemplate>
<Border x:Name=""grid"" Background=""Red"">
<ContentPresenter>
<ContentPresenter.Content>
<TextBlock Margin=""4"" FontSize=""15"" Text=""{TemplateBinding Content}""/>
</ContentPresenter.Content>
</ContentPresenter>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding=""{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TabItem}},Path=IsSelected}"" Value=""True"">
<Setter TargetName=""grid"" Property=""Background"" Value=""Red""/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>";
ResourceDictionary rd = XamlReader.Parse(customResources) as ResourceDictionary;
redstyle = rd["RedStyle"] as Style;
}
else if (State == State.Terminated) //set the tab back to standard once we are finished
{
if (ChartControl != null && defaultstyle != null)
{
this.Dispatcher.InvokeAsync(() =>
{
var chartWindow = Window.GetWindow(ChartControl.Parent) as Chart;
foreach (TabItem tab in chartWindow.MainTabControl.Items)
{
if (tab.Header.ToString() == Instrument.FullName)
{
tab.Style = defaultstyle;
break;
}
}
});
}
}
}
protected override void OnBarUpdate() //runs fine when enabling strategy from chart, but not from control centre
{
if (State == State.Realtime)
{
if (ChartControl != null)
{
this.Dispatcher.InvokeAsync(() =>
{
var chartWindow = Window.GetWindow(ChartControl.Parent) as Chart;
foreach (TabItem tab in chartWindow.MainTabControl.Items)
{
if (tab.Header.ToString() == Instrument.FullName)
{
if (tab.Style != redstyle) defaultstyle = tab.Style;
tab.Style = redstyle; //error occurs here
break;
}
}
});
}
}
}
}
Comment