Reputation: 1758
I'm trying to use Commands for the application I'm writing so I can simply have the conditions under which the Buttons on the UI are enabled inside the CanExecute condition in the ViewModel instead of a MultiBinding inside the UI XAML (or even worse, managing the IsEnabled states in code-behind).
Now I want to start a operation which sends and fetches some data via a SerialPort, which are written to a file in the end. This takes several minutes.
[Model]
+ DoLongOperation(string port) : void // Starts a timer to gather data, takes several minutes
+ LongOperationDone : event // fires when operation finished
+ Result: LongOperationResults // set when operation finished (successfully)
+ LongOperationRunning: bool // INPC
+ AbortOperation(): void
- port: SerialPort
Here's what my non-MVVM approach would be:
[UI]
<ComboBox x:Name"port" />
<Button Click="ButtonClick">
<Button.IsEnabled>
<!-- bind to model directly -->
<MultiBinding Converter="{StaticResource AllTrueConverter}">
<!-- multiple conditions: port selected, operation not running... -->
</MultiBinding>
</Button.IsEnabled>
Do the long operation
</Button>
[UI Code-Behind]
private void ButtonClick(object sender, RoutedEventArgs e)
{
// unsubscribe first, to avoid multiple execution
// logic inside UI! "not good", as far as I know
longOp.LongOperationDone += (s, e2) => {var result = longOp.Result; var filename = result.WriteToFile(); Process.Start(filename); }
longOp.DoLongOperation((string)port.SelectedItem);
}
Trying to use Commands:
[UI]
<ComboBox x:Name"port" SelectedItem="{Binding PortName}"/>
<Button Command="{Binding LongOperationCommand}">Do the long operation</Button>
[ViewModel]
+ LongOperationCommand : RelayCommand // Execute: LongOperation.DoLongOperation(PortName); CanExecute: !String.isNullOrEmpty(PortName) && !LongOperation.LongOperationRunning
+ PortName: String // INPC
# Model: LongOperation
However, using Commands, I'm not sure how I can do the same as in the code-behind example.
So, actually multiple questions:
Upvotes: 0
Views: 134
Reputation: 1076
I try to answer:
The command is generally the right way, because you should avoid Events in this pattern. But this has nothing to do with longrunning or short running processes. For Long running process you should think about creating a Task
that runs in Background
Generally the ViewModel should not fire Events because the View does not handle them, beside NotifyChanged. You should set states in ViewModel with bool Properties like LongOperationRunning:bool
You should set something like LongOperationRunning
to tell the View that a Long running process is running and the view should Show a progressbar or whatever you Need in your view. Generally you have to tell the view about the state. And the view has to react depending on the ViewModel state.
Hope tis helps a bit
References:
Asynchronous Programming with Async and Await (C# and Visual Basic)
Upvotes: 1