Reputation: 195
I am developing a WPF/NetCore3.1 application with MVVM. In the view there is a button which is bound to a RelayCommand. The ViewModel is in a different class library than the View. In the ViewModel a timer is started which increments a variable every second and triggers the CanExecuteChanged event of the RelayCommand.
Here is my ViewModel:
public ImportExportViewModel()
{
MakeOfferCommand = new RelayCommand(MakeOffer, CanMakeOffer);
Timer t = new Timer(1000);
t.Elapsed += T_Elapsed;
t.Start();
}
private void T_Elapsed(object sender, ElapsedEventArgs e)
{
ElapsedTime++;
MakeOfferCommand.RaiseCanExecuteChanged();
}
private void MakeOffer()
{
// TODO Make Offer
}
private bool CanMakeOffer()
{
return ElapsedTime < 60;
}
And here the RaiseCanExecuteChanged:
public void RaiseCanExecuteChanged()
{
var handler = CanExecuteChanged;
if (handler != null)
{
handler(this, new EventArgs());
}
}
But here I get an InvalidOperationException: the calling thread cannot access this object because the object is owned by another thread.
Normally I would execute a Dispatcher.Invoke() here, but that seems not to exist in .NetCore3.1.
Can anyone tell me how I can still make cross-thread calls?
Upvotes: 3
Views: 2197
Reputation: 169420
You could inject your view model with an IDispatch
interface that you implement in each platform:
Interface:
public interface IDispatch
{
bool CheckAccess();
void Invoke(Action action);
}
View Model:
public IDispatch Dispatch { get; set; }
private void T_Elapsed(object sender, ElapsedEventArgs e)
{
if (Dispatch != null && !Dispatch.CheckAccess())
Dispatch.Invoke(new Action(() => { /* do something */ }));
...
}
WPF implementation:
public class WpfDispatch : IDispatch
{
private readonly Dispatcher _dispatcher;
public WpfDispatch(Dispatcher dispatcher) =>
_dispatcher = dispatcher;
public bool CheckAccess() => _dispatcher.CheckAccess();
public void Invoke(Action action) => _dispatcher.Invoke(action);
}
Upvotes: 3