Trying to get clear about flaw in this code:
Scenario 1:
This scenario uses data binding and causes the very well known cross-thread exception in the var rand_x = CGFloat(arc4random_uniform(maxXValue))
var rand_y = CGFloat(arc4random_uniform(maxYValue))
method in the NotifyPropertyChanged()
class.
Scenario 2:
This scenario solves the problem by subscribing to the PriceSimulator
event of PropertyChanged
, eliminates the cross-thread issue but has to avoid data binding altogether.
Assuming Scenario 1 was the intended scenario and assuming one has no knowledge of the inner workings of PriceSimulator
and just wanted to bind to the PriceSimulator
property, what is the core issue here?
Form1.cs:
Price
PriceSimulator.cs:
public partial class Form1 : Form
{
PriceSimulator simul;
Action labelAction;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
labelAction = new Action(SetLabel);
simul = new PriceSimulator(5, 1000);
//Scenario 1:
//Use data binding and get Cross-Thread exception
//label1.DataBindings.Add("Text", simul, "Price");
//Scenario 2:
//This works fine
//Subscribe to PropertyChanged event
simul.PropertyChanged += task_PropertyChanged;
simul.Start();
}
//Scenario 2:
void task_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (label1.InvokeRequired)
Invoke(labelAction);
else SetLabel();
}
private void SetLabel()
{
label1.Text = simul.Price.ToString("C2");
}
}
答案 0 :(得分:1)
您必须在PriceSimulator类中拥有当前上下文:
private readonly SynchronizationContext _context = SynchronizationContext.Current;
现在您已拥有上下文,您可以使用它来更新UI:
_context.Post(delegate
{
if (++Price >= max)
timer.Dispose();
}, null);