I am working ona WPF application that has a toolbar/menu that will have the use for several custom commands. Probably around 15-20. I have seen documentation on how to create custom commands, but none of them necessarily apply to what I am trying to do.
I am using a controller to handle the business logic in my application, and I am trying to keep my view from doing any logic at all.
What I would like to do is create a directory in my project that holds the custom command classes so that I can decouple them from the controller and the view, but I would still like them to be called from the view such as a normal commmand is.
I have also seen the use of a DelegateCommand class, but am not quite sure if that is the direction I want to head in.
I would like to be able to have an arbitrary custom command class such as the following
public CustomCommand: ICommandd
{
public bool CanExecute(object parameter)
{
//arbitrary logic
}
public void Execute(object parameter)
{
}
}
The idea is that I would have 10-20 of these, and I want to keep them separate from everything else, and have them be called when needed.
I know that there is a way I can separate my custom commands, but am not quite sure.
I am new to using commands, so I still am trying to get a hold of the concept.
thanks,
The concept is you bind a command to a button and the command drives two properties of this button: "on click" and "enabled" resulting in the interface you posted.
The main reason you want to do commanding is to be able to bind button clicks to actions in your view model.
If you create one custom command which takes an action as constructor parameter you can wire methods from your view model directly to your command.
public class RelayCommand: ICommandd
{
Action action;
Func<bool> canExecute;
public RelayCommand(Action action) : this(action, () => true) {}
public RelayCommand(Action action, Func<bool> canExecute)
{
this.action = action;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute();
}
public void Execute(object parameter)
{
action();
}
}
Usage in your view model would be
public RelayCommand SaveCommand { get; set; }
SaveCommand = new RelayCommand(OnSave);
public void Save()
{
// save logic...
}
If you want to wire CanExecute, too you can use the second ctor and provide a CanSave Method.
public RelayCommand SaveCommand { get; set; }
SaveCommand = new RelayCommand(OnSave, CanSave);
public void Save()
{
// save logic...
}
public bool CanSave()
{
return // ...
}
As you may noticed I dropped the command parameter in my implementation. This will be sufficient in most cases and saves you extra parameters in your handler methods. For the 10% left I implemented a RelayCommand<T> which takes an Action instead of Action and changes the Execute method to
public void Execute(object parameter)
{
action((T)parameter);
}
which requires a parameterized handler
SaveCommand = new RelayCommand<SomeType>(OnSave);
public void Save(SomeType toSave)
{
// save logic using parameter
}
This saves you all casting issues you encounter when using object variables and keeps your view models type safe.
Use RelayCommand, it doesn't require you to create a class for each command, you simply add both methods into the constructor as lambda expressions/delegates.
I use it all around my projects, it is a real time-saver.
I have ended up answering my own question through the following post,
http://www.codeproject.com/KB/WPF/CentralizingWPFCommands.aspx?display=Print
Related
I used caliburn.micro version 4.0.173 and .NET framework 4.8.
Requirement is as below description
I have a script ViewModel. There is a button to click it and pop up a setting ViewModel.
After setting ViewModel appear, it can be setup some parameters and click button to confirm these settings. When confirm button is clicked, it can trigger to script ViewModel from setting ViewModel.
I refer this link to do this. To create a class is for event in project folder. But, when I publish in setting View, that doesn't work to subscribe in Handle of script viewmodel. How can I pass these parameters to another view model?
Thank you.
Event
public class FooEvent
{
public bool Foo { get; set; }
public FooEvent(bool foo)
{
Foo = foo;
}
}
Setting ViewModel
public class SettingViewModel : Screen
{
private IEventAggregator _eventAggregator;
public ItemViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
public void PublishFooEvent()
{
_eventAggregator.PublishOnUIThreadAsync(new FooEvent(true));
}
public void BtnSaveItem()
{
PublishFooEvent();
}
}
Script ViewModel
public class ScriptViewModel : Screen, IHandle<FooEvent>
{
private readonly IEventAggregator _eventAggregator;
[ImportingConstructor]
public ScriptViewModel(IEventAggregator eventAggregator)
{
this._eventAggregator = eventAggregator;
_eventAggregator.SubscribeOnUIThread(this);
}
public void Handle(FooEvent fooEvent)
{
}
}
I find out that problem is in other handle.
When I added interface and fixed error automatically.
IDE creates a new method (HandleAsync) which I didn't notice it.
Therefore, I type another handle manually.
It always works on HandleAsync after trigger with another viewmodel.
ASP.NET Boilerplate have EventBus system and we have events
EntityCreatingEventData
EntityCreatedEventData
EntityDeletingEventData
EntityDeletedEventData
…
But these events work after calling SaveChanges() (data already in DB). We want event system before calling SaveChanges(), when data is not written in DB yet
We also want recursive event system, for example :
creating object A => call EntityCreatingBeforeSaveEventData(a) => in this handle we create new object B and call Repository.Insert(b) => call EntityCreatingBeforeSaveEventData(b)...
And this process calling while exist any modification in DB Context.
Dependent on entity.Id
It is not possible to have a domain event system before calling SaveChanges().
ASP.NET Boilerplate detects changes when calling SaveChanges().
Recursive events can cause an infinite loop — see #1616.
An object with an Id that has not been set (auto-generated) cannot be identified.
If you are dependent on such a system, then it may be poor separation of concerns.
Independent of entity.Id
You can use IEventBus directly.
Trigger event:
public class AManager : DomainService, IAManager
{
public void CreateA()
{
var a = new A();
Repository.Insert(a);
EventBus.Trigger(new EntityCreatingBeforeSaveEventData<A>
{
Property = a.SomeProperty // Can pass other properties
});
}
}
public class BManager : DomainService, IBManager
{
// Similar to above
}
Handle event:
public class AHandler : IEventHandler<EntityCreatingBeforeSaveEventData<A>>, ITransientDependency
{
public IBManager BManager { get; set; }
public void HandleEvent(EntityCreatingBeforeSaveEventData<A> eventData)
{
var aSomeProperty = eventData.Property;
BManager.CreateB();
}
}
I'm building WPF application which downloads links to articles from website and displays them in a grid.
Summary of the problem:
The problem I'm hitting is that I have downloading logic in the model which does not have access to the ObservableCollection Articles (which is defined in my ViewModel and bound to DataGrid).
How should I access this collection to update it as I'm downloading new articles (so that data grid will keep adding new ones one by one)?
Details:
Here's overview of my app which implements MVVM pattern (I cut some of the not important parts to keep it easy to read):
DisplayWindow.xaml
Is binding source to PresenterViewModel.cs and ItemSource is set to Articles which is ObservableCollection (see below)
<Grid DataContext="{Binding Source={StaticResource presenterViewModel}}">
<DataGrid ItemsSource="{Binding Articles}">
<DataGrid.Columns>
<DataGridTextColumn Header="Url" Binding="{Binding Url}"/>
...
</DataGrid.Columns>
</DataGrid>
</Grid>
it also has button which triggers downloading of the article links via
<Button Content="Download" Command="{Binding DownloadArticles, Mode=OneWay}"/>
DownloadArticles method is part of PresenterViewModel and returns instance of DownloadCommand which implements interface ICommand.
PresenterViewModel.cs
contains ObservableCollection<Article> Articles
private ObservableCollection<Article> articles;
public ObservableCollection<Article> Articles
{
get { return articles; }
set
{
articles = value;
RaisePropertyChangedEvent("Articles");
}
}
public ICommand DownloadArticles
{
get
{
return downloadCommand;
}
}
DownloadCommand contains reference to PresenterViewModel and in Execute method calls it's method DownloadArticles which calls DownloadArticles in the Article model itself.
in DownloadCommand.cs:
public void Execute(object parameter)
{
presenterViewModel.DownloadArticles();
}
Solutions I was considering:
Now, the problem is I'm in DownloadArticles method in Article.cs model and need to update Articles ObservableCollection which is part of PresenterViewModel...
how do I do that? The DownloadArticles method runs downloading logic in a separate thread.
Should I pass the reference to PresenterViewModel to the DownloadArticles method of the model?
This seems like an easy way to do it, however it just doesn't feel right - I don't think model should be coupled to the ViewModel and in this case one of the methods would accept PresenterViewModel object.
Another option would be having downloading logic directly in PresenterViewModel, but that doesn't feels right either as I'd prefer my ViewModel to be lightweight and not containing any logic.
What would be the best solution in this case? If you think my architecture is fundamentally wrong, please let me know what would be the best way of structuring it in this case.
I really appreciate your advices on this!
Now, the problem is I'm in DownloadArticles method in Article.cs model
and need to update Articles ObservableCollection which is part of
PresenterViewModel... how do I do that?
What you need to do is to separate your data access logic into another layer and inject it into your ViewModel as a dependency. By doing so you won't couple any of data access logic to your ViewModel because its task should be only to expose Model to the View and respond to user input.
Suppose that your model looks something like this:
public class Article : INotifyPropertyChanged
{
private string _url;
public string Url
{
get
{
return _url;
}
set
{
_url = value;
PropertyChanged("Url");
}
}
}
All the data access logic goes to a separate layer which I will call DataService. Its job is to access the external resource and download articles:
public interface IDataService
{
IList<Article> DownloadArticles();
}
public class DataService : IDataService
{
public IList<Article> DownloadArticles()
{
var articles = new List<Article>();
// you actually download articles here
return articles;
}
}
The data access layer is then injected in your ViewModel
public class PresenterViewModel : BaseViewModel
{
private readonly IDataService _dataService;
public PresenterViewModel(IDataService dataService)
{
_dataService = dataService;
}
}
Finally when user requests to download articles by triggering DownloadCommand you delegate this job to your service and wait for result which then will be exposed to your View by ObservableCollection<Article> Articles property of your ViewModel:
// your DownlodArticles command's execute method
public void Execute(object parameter)
{
var articles = _dataService.DownloadArticles();
Articles = new ObservableCollection(articles);
}
If for some reason you don't want to use dependency injection, you can implement your DataService as singleton and call it from your ViewModel:
public class DataService
{
private static DataService _instance;
public static DataService Instance
{
get
{
if (_instance == null)
{
_instance = new DataService();
}
return _instance;
}
}
public IList<Articles> DownloadArticles()
{
// ...
}
}
public void Execute(object parameter)
{
var articles = _DataService.Instance.DownloadArticles();
Articles = new ObservableCollection(articles);
}
UPDATE:
Your data service GetArticles method:
public Task DownloadArticles(ICollection<Article> articles)
{
// clear the collection if neccessary
articles.Clear();
return Task.Run(() =>
{
// load articles one by one and add them to the collection
}
}
Your ViewModel command execute method:
private async void Execute(object parameter)
{
await _dataService.LoadArticles(Articles);
}
Have been learning about MVP and have tried writing a test app using it in WinForms. I'm struggling to find a well explained example on how to navigate between my forms/views. As an example, the program starts and I want to show a login dialog then go into my main view if the login was successful. At the moment, my Main method looks something like this:
static void Main()
{
var loginView = Injector.Resolve<ILoginView>();
if (loginView.DoLogin() != LoginResult.OK) return;
var mainView = Injector.Resolve<IMainView>();
Application.Run(mainView); // won't work as mainView isn't a form
}
The Injector object is just a wrapper around an IoC tool (currently StructureMap). The thing is, I've read that I shouldn't really be manually creating instances via the Injector as they should really be done via constructor injection.
I've managed to do this up to a point but not when it comes to navigation. I can't think of an elegant way of moving through my views and was wondering if anyone here might shed some light on this? I've read a little on application controllers but have not found an example to show it clearly.
In regards to the navigation question:
I've managed to do this up to a point but not when it comes to
navigation. I can't think of an elegant way of moving through my views
and was wondering if anyone here might shed some light on this? I've
read a little on application controllers but have not found an example
to show it clearly.
Below is a simplified version of a construct I've used. Note that the setup and tear down hooks are called automatically when the NavigateTo method is called. Also, +1 to #AlexBurtsev, as his answer hints at this very same approach.
// Presenter can and should offer common services for the
// subclasses
abstract class Presenter
{
public void Display()
{
OnDisplay();
}
public void Dismiss()
{
OnDismiss();
}
protected virtual OnDisplay() // hook for subclass
{
}
protected virtual OnDismiss() // hook for subclass
{
}
private NavigationManager _navMgr;
internal NavigationMgr NavigationManager
{
get
{
return _navMgr;
}
set
{
_navMgr = value;
}
}
}
// NavigationManager is used to transition (or navigate)
// between views
class NavigationManager
{
Presenter _current;
// use this override if your Presenter are non-persistent (transient)
public void NavigateTo(Type nextPresenterType, object args)
{
Presenter nextPresenter = Activator.CreateInstance(nextPresenterType);
NavigateTo(nextPresenter);
}
// use this override if your Presenter are persistent (long-lived)
public void NavigateTo(Presenter nextPresenter, object args)
{
if (_current != null)
{
_current.Dismiss()
_current.NavigationMgr = null;
_current = null;
}
if (nextPresenter != null)
{
_current = nextPresenter;
_current.NavigationMgr = this;
_current.Display(args);
}
}
}
class MainMenuPresenter : Presenter
{
private IMainMenuView _mainMenuView = null;
// OnDisplay is your startup hook
protected override void OnDisplay()
{
// get your view from where ever (injection, etc)
_mainMenuView = GetView();
// configure your view
_mainMenuView.Title = GetMainTitleInCurrentLanguage();
// etc
// etc
// listen for relevent events from the view
_mainMenuView.NewWorkOrderSelected += new EventHandler(MainMenuView_NewWorkOrderSelected);
// display to the user
_mainMenuView.Show();
}
protected override void OnDismiss()
{
// cleanup
_mainMenuView.NewWorkOrderSelected -= new EventHandler(MainMenuView_NewWorkOrderSelected);
_mainMenuView.Close();
_mainMenuView = null;
}
// respond to the various view events
private void MainMenuView_NewWorkOrderSelected(object src, EventArgs e)
{
// example of transitioning to a new view here...
NavigationMgr.NavigateTo(NewWorkOrderPresenter, null);
}
}
class NewWorkOrderPresenter : Presenter
{
protected override void OnDisplay()
{
// get the view, configure it, listen for its events, and show it
}
protected override void OnDismiss()
{
// unlisten for events and release the view
}
}
I haven't used WinForms for a long time, but I'll try to answer this. I would use the same strategy as WPF Prism do.
About MainView and Application.Run:
Create a main Region (root Form), with empty container inside which can hold UserControl (I forgot exact class names), then when you need to switch root view, you do RootView.SetView(UserControl view) which will do something like Form.Clear(), Form.AddChild(view).
About the navigation and using container:
You could create a service for navigation: INavigationService which you inject in constructors with method like INavigationService.NavigateView(String(or Type) viewName, params object[] additionalData)
You can insert a method in mainView that returns the actual form.Then you can call
Mainview:IMainView
{
Form GetView()
{
//return new Form();
}
}
In Main you can call ,
Application.Run(mainView.GetView())
My View calls a method in ViewModel to Fetch Data. After fetching the data, I build my View(Grid) based on the data that got back from the ViewModel.
getData() Method in the View Model runs in a BackgroundWorker thread. Now my question is how do I get back to View after the View is done fetching all the data?
ViewModel
{
getData()
{
WorkerMethods()
WorkerCompletedMethod()
{
Refresh()
}
}
Refresh()
{
WorkerMethod()
WorkerCompleted()
{
data - Retrieved.
This is where all the calls are really DONE
}
}
}
From the View, I will be calling
View()
{
VM.getData()
//Before I call this method, I want to make sure Refresh() is completed
BuildUI()
}
I want the BuildUI() method to be executed only after the VM.getData() is executed fully and in turn is done with Refresh() method as well which is what has the Data I need to be able to build the UI Dynamically.
This is what I am going to do. Please correct me if this is not right approach.
In the View code behind,
View
{
public delegate void DelegateRefresh();
Init()
{
DelegateRefresh fetcher = RefreshData;
fetcher.BeginInvoke(null, null);
}
public void RefreshData()
{
_viewModel.GetData();
**while (_viewModel.IsBusy)**
{
continue;
}
BuildUI();
}
BuildUI()
{
//Code to build the UI Dynamically using the data from VM.
}
You should retrieve the data once the BackgroundWorker has completed its work. Your view model should implement the INotifyPropertyChanged interface and expose the data through a property that the view binds to. The view model can then notify the view when the data is available (i.e. the BackgroundWorker has completed its work).
One approach is to use messaging. That is, register your message on the view, then send a message from the view model to the view, when this message is received then you could call your BuildUI method.
For example, if you were using the MvvmLight framework, here's one way of passing back an error message to show up in a dialog. You might not want to show a dialog (I had this code on hand), but the process is the same, it's just a different message type to register and send.
ViewModel:
public class ErrorMessage : DialogMessage
{
// See MvvmLight docs for more details, I've omitted constructor(s)
/// <summary>
/// Registers the specified recipient.
/// </summary>
/// <param name="recipient">The recipient of the message.</param>
/// <param name="action">The action to perform when a message is sent.</param>
public static void Register(object recipient, Action<ErrorMessage> action)
{
Messenger.Default.Register<ErrorMessage>(recipient, action);
}
/// <summary>
/// Sends error dialog message to all registered recipients.
/// </summary>
public void Send()
{
Messenger.Default.Send<ErrorMessage>(this);
}
}
public class SomeViewModel : ViewModelBase
{
public void SendErrorMessage(string message)
{
var errorMessage = new ErrorMessage(message);
errorMessage.Send();
// Or in your case, when the background worker is completed.
}
}
View:
public partial class SomeView : Window
{
public SomeView()
{
InitializeComponent();
ErrorMessage.Register(this, msg =>
{
MessageBoxResult result = MessageBox.Show(msg.Content, msg.Caption,
msg.Button, msg.Icon, msg.DefaultResult, msg.Options);
msg.ProcessCallback(result);
// Or in your case, invoke BuildUI() method.
});
}