B
Bill Richards
I run the Unit Test below in debug mode, and I place breakpoints in the
CrossThreadClass on the lines
Owner = p;
and
Dispatcher.Invoke(DispatcherPriority.Normal, new
CrossThreadDelegate(UpdateOwnerAndTokenCount), e.Data);
The Dispatcher line is hit, but the Owner line is never called, even if I
set my thread to sleep for a whole second.
Have I missed something with regards to making cross threaded calls to
DependencyProperty and using the
DependencyObject/Dispatcher/DispatcherObject
Thanks in advance
// -----THE UNIT
TEST--------------------------------------------------------------------------------------------------//
[Test]
public void
WhenAPositionExplodes_ShouldSeeTheNeighbourUnderPlayersControl()
{
PlayerManager manager =
PlayerManager.NewManager(PlayerNumbers.One);
Player player = manager.AddNewPlayer("Player One");
var board = BoardBuilder.CreateBoard(5, 3);
CrossThreadClass corner = board.GetByLocation(new
LocationOnBoard(1, 1));
corner.Owner = player;
corner.AddToken();
corner.AddToken();
corner.AddToken();
CrossThreadClass neighbour = board.GetByLocation(new
LocationOnBoard(2, 1));
System.Threading.Thread.Sleep(20);
Assert.That(neighbour.CurrentTokenCount,
Is.EqualTo(TokenCounts.One));
Assert.That(neighbour.Owner, Is.EqualTo(player));
}
// -----THE
CLASS -----------------------------------------------------------------------------------------------------//
public class CrossThreadClass : DependencyObject
{
public delegate void CrossThreadDelegate(Player p);
public event EventHandler<EventArgs<Player>> OnOwnerChanged;
public event EventHandler<EventArgs<Player>> OnExploding;
public static readonly DependencyProperty OwnerProperty =
DependencyProperty.Register("Owner", typeof(Player)
, typeof(CrossThreadClass)
, new PropertyMetadata(null
, (s, e) =>
RaiseOwnerChangedEventIfRequired((CrossThreadClass)s
, (Player)e.NewValue)));
public Player Owner
{
get { return (Player)GetValue(OwnerProperty); }
set { SetValue(OwnerProperty, value); }
}
private static void
RaiseOwnerChangedEventIfRequired(CrossThreadClass sender, Player newOwner)
{
if (sender.OnOwnerChanged == null)
return;
new Thread(args =>
{
var objects = (object[])args;
var position = (CrossThreadClass)objects[0];
var player = (Player)objects[1];
position.OnOwnerChanged(position, new
EventArgs<Player>(player));
}).Start(new object[] { sender, newOwner });
}
private void UpdateOwnerAndTokenCount(Player p)
{
Owner = p;
AddToken();
}
public void AddToken()
{
// ... stuff to add a token
}
private void NeighbourExplodingEventHandler(object sender,
EventArgs<Player> e)
{
if (CheckAccess())
UpdateOwnerAndTokenCount(e.Data);
else
Dispatcher.Invoke(DispatcherPriority.Normal, new
CrossThreadDelegate(UpdateOwnerAndTokenCount), e.Data);
}
internal void RegisterNeighbourExplodingEvent(ref CrossThreadClass
ctc)
{
ctc.OnExploding += NeighbourExplodingEventHandler;
}
}
CrossThreadClass on the lines
Owner = p;
and
Dispatcher.Invoke(DispatcherPriority.Normal, new
CrossThreadDelegate(UpdateOwnerAndTokenCount), e.Data);
The Dispatcher line is hit, but the Owner line is never called, even if I
set my thread to sleep for a whole second.
Have I missed something with regards to making cross threaded calls to
DependencyProperty and using the
DependencyObject/Dispatcher/DispatcherObject
Thanks in advance
// -----THE UNIT
TEST--------------------------------------------------------------------------------------------------//
[Test]
public void
WhenAPositionExplodes_ShouldSeeTheNeighbourUnderPlayersControl()
{
PlayerManager manager =
PlayerManager.NewManager(PlayerNumbers.One);
Player player = manager.AddNewPlayer("Player One");
var board = BoardBuilder.CreateBoard(5, 3);
CrossThreadClass corner = board.GetByLocation(new
LocationOnBoard(1, 1));
corner.Owner = player;
corner.AddToken();
corner.AddToken();
corner.AddToken();
CrossThreadClass neighbour = board.GetByLocation(new
LocationOnBoard(2, 1));
System.Threading.Thread.Sleep(20);
Assert.That(neighbour.CurrentTokenCount,
Is.EqualTo(TokenCounts.One));
Assert.That(neighbour.Owner, Is.EqualTo(player));
}
// -----THE
CLASS -----------------------------------------------------------------------------------------------------//
public class CrossThreadClass : DependencyObject
{
public delegate void CrossThreadDelegate(Player p);
public event EventHandler<EventArgs<Player>> OnOwnerChanged;
public event EventHandler<EventArgs<Player>> OnExploding;
public static readonly DependencyProperty OwnerProperty =
DependencyProperty.Register("Owner", typeof(Player)
, typeof(CrossThreadClass)
, new PropertyMetadata(null
, (s, e) =>
RaiseOwnerChangedEventIfRequired((CrossThreadClass)s
, (Player)e.NewValue)));
public Player Owner
{
get { return (Player)GetValue(OwnerProperty); }
set { SetValue(OwnerProperty, value); }
}
private static void
RaiseOwnerChangedEventIfRequired(CrossThreadClass sender, Player newOwner)
{
if (sender.OnOwnerChanged == null)
return;
new Thread(args =>
{
var objects = (object[])args;
var position = (CrossThreadClass)objects[0];
var player = (Player)objects[1];
position.OnOwnerChanged(position, new
EventArgs<Player>(player));
}).Start(new object[] { sender, newOwner });
}
private void UpdateOwnerAndTokenCount(Player p)
{
Owner = p;
AddToken();
}
public void AddToken()
{
// ... stuff to add a token
}
private void NeighbourExplodingEventHandler(object sender,
EventArgs<Player> e)
{
if (CheckAccess())
UpdateOwnerAndTokenCount(e.Data);
else
Dispatcher.Invoke(DispatcherPriority.Normal, new
CrossThreadDelegate(UpdateOwnerAndTokenCount), e.Data);
}
internal void RegisterNeighbourExplodingEvent(ref CrossThreadClass
ctc)
{
ctc.OnExploding += NeighbourExplodingEventHandler;
}
}