I have problem passing object to secondary view in MVVM light WPF. I have main view Model. follow of operation. I am able to wire things up using MVVM light and Modren UI navigation Services. The issue is that i am not able to send object of Main Customer view model to secondary View Model. I want to set data-context of target View from source View Model. I have tried this but does not seem to be working. I prefer no code behind and i have spent a lot of time without any success.
public virtual void NavigateTo(string pageKey, object parameter)
{
lock (_pagesByKey)
{
if (!_pagesByKey.ContainsKey(pageKey))
{
throw new ArgumentException(string.Format("No such page: {0}. Did you forget to call NavigationService.Configure?", pageKey), "pageKey");
}
var frame = GetDescendantFromName(Application.Current.MainWindow, "ContentFrame") as ModernFrame;
// Set the frame source, which initiates navigation
if (frame != null)
{
frame.Source = _pagesByKey[pageKey];
//i Dont know if this should work or not
frame.DataContext = parameter;
}
Parameter = parameter;
_historic.Add(pageKey);
CurrentPageKey = pageKey;
}
}
any help will be greatly appreciated. I just need to how i can set the datacontext of target View without using code behind. Thanks
There's multiple possibilities but one that does not create dependencies between your viewmodels is to use pub/sub system in MVVMLight. Basically it goes like this:
When you select some entity from your view and transition to another, viewmodel sends a message that carriers that given entity along. In the other viewmodel you receive the message and set some property accordingly (for editing, adding new entity, etc.)
// mainviewmodel
Messenger.Default.Send(new MyMessage(myObj));
// otherviewmodel
Messenger.Default.Register<MyMessage>(this, message =>
{
/* do something with message.MyObj */
});
// mymessage
public class MyMessage : MessageBase
{
...
public MyObj MyObj { get; set; }
}
Related
My view has a control inside of it that is capable of generating an image that is saved at a path I can specify (along with some other data). I don't own this control and can't get the interface to generate an image changed. I'm not quite sure how to handle this with MVVM.
The quick and dirty way would be for my view to define a method that takes the desired path, and have the viewmodel call that method.
View:
public void GenerateImage(string path) {
_control.SaveImage(path);
}
ViewModel:
(actually this is the body of a Command) {
var path = GeneratePath();
_view.GenerateImage(path);
...
}
I don't like this because I get the feeling that viewmodels are not meant to directly reference the view, instead they represent the view's state and communicate via property bindings. It works, and I'm doing this while waiting on answers. I'd like to find a way around it.
I could get cute and have the view pass a reference to the control to a Command (I'm in Xamarin Forms) via the Execute() parameter, and have the command cast and make the call. This seems like lipstick on a pig since it makes the viewmodel still aware of a particular class inside the view. But in writing this paragraph I think I came up with a solution I like.
I /could/ create:
interface IGenerateImage {
void GenerateImage(string path);
}
The obvious implementation would delegate the call to an encapsulated control. I feel like if the view passes an IGenerateImage then I'm not creating the viewmodel-to-view dependency that I'm trying to avoid, and I can test the logic without needing to instantiate expensive UI classes.
I like that answer, but I'm pretty sure there's an obvious solution I'm missing. Is there some other useful pattern for handling it? Or is it not a big deal if the viewmodel references the view?
You never want the View Model to know anything about the View.
It's a little unclear what you can and can't change in your post, so I'm assuming you can change the V/VM, but not _control.
The easiest way is to create an event in the View Model that the View can subscribe to.
Something like this:
View:
// Constructor
public View()
{
// However you're setting your VM, i.e. DI or new-ing up the VM
// Subscribe to the event
vm.ImageGeneratedEvent += this.OnImageGeneratedEvent;
}
private void OnImageGeneratedEvent(object sender, ImageGeneratedEventArgs args)
{
// Call your SaveImage in the event handler
_control.SaveImage(args.Path);
}
View Model:
public event EventHandler<ImageGeneratedEventArgs> ImageGeneratedEvent;
// Command body
{
var path = GeneratePath();
// Send event to the View
this.NotifyImageGeneratedEvent(path)
}
private void NotifyImageGeneratedEvent(string path)
{
ImageGeneratedEventArgs args = new ImageGeneratedEventArgs(path);
if (this.ImageGeneratedEvent!= null)
{
this.ImageGeneratedEvent(this, args);
}
}
ImageGeneratedEventArgs:
public class ImageGeneratedEventArgs : EventArgs
{
public string Path { get; set; }
public ImageGeneratedEventArgs(string path)
{
this.Path = path;
}
}
I'm new on Caliburn Micro and want some advice on which path to take to devolop my app interface and navigation between views.
My idea is to have a MainWindow which will contain a menu of buttons, each one related with a specific view. Each view will be stored in a separated WPF UserControl. The mainWindow will also contain a TabControl bound to an ObservableCollection of tabs on viewmodel. Everytime a button on menu is clicked, I want to add a new tab with a ContentPresenter inside that will dynamically load a view and its corresponding viewmodel.
So my questions:
1) Should I use a Screen Collection here?
2) Should the UserControl implement Screen interface?
3) How do I tell MainWindow ViewModel which view to load on the new added tab maintaining viewmodels decoupled?
Thanks to everyone in advance.
UPDATE
After a lot of reading and some help of the community I managed to resolve this. This is the resultant AppViewModel:
class AppViewModel : Conductor<IScreen>.Collection.OneActive
{
public void OpenTab(Type TipoVista)
{
bool bFound = false;
Screen myScreen = (Screen)Activator.CreateInstance(TipoVista as Type);
myScreen.DisplayName = myScreen.ToString();
foreach(Screen miItem in Items)
{
if (miItem.ToString() == myScreen.ToString())
{
bFound = true;
ActivateItem(miItem);
}
}
if (!bFound) ActivateItem(myScreen);
}
public ObservableCollection<MenuItem> myMenu { get; set; }
public ObservableCollection<LinksItem> myDirectLinks { get; set; }
public ICommand OpenTabCommand
{
get
{
return new RelayCommand(param => this.OpenTab((Type) param), null);
}
}
public AppViewModel()
{
OpenTab(typeof(ClientsViewModel));
MenuModel menu = new MenuModel();
myMenu = menu.getMenu();
myDirectLinks = menu.getLinks();
}
public void CloseTab(Screen param)
{
DeactivateItem(param, true);
}
}
I have to keep the ICommand from OpenTabCommand because the name convention of Caliburn.micro doesn't seems to work inside DataTemplate. Hope it could help someone else. Thanks to all
I've done something very similar using Caliburn.Micro, and based it on the SimpleMDI example included with the examples, with a few tweaks to fit my needs.
Much like in the example, I had a main ShellViewModel:
public class ShellViewModel : Conductor<IScreen>.Collection.OneActive
{
}
with a corresponding ShellView containing a TabControl - <TabControl x:Name="Items">, binding it to the Items property of the the Conductor.
In this particular case, I also had a ContextMenu on my ShellView, bound (using the Caliburn.Micro conventions), to a series of commands which instantiated and Activated various other ViewModels (usually with a corresponding UserControl, using the ActivateItem method on the Conductor.
public class YourViewModel: Conductor<IScreen>.Collection.OneActive
{
// ...
public void OpenItemBrowser()
{
// Create your new ViewModel instance here, or obtain existing instance.
// ActivateItem(instance)
}
}
In that case, I didn't require the ViewModels to be created with any particular dependency, or from any other locations in the program.
At other times, when I've needed to trigger ViewModel from elsewhere in the application, I've used the Caliburn.Micro EventAggregator to publish custom events (e.g. OpenNewBrowser), which can be handled by classes implementing the corresponding interface (e.g. IHandle<OpenNewBrowser>), so your main ViewModel could have a simple Handle method responsible for opening the required View:
public class YourViewModel: Conductor<IScreen>.Collection.OneActive, IHandle<OpenNewBrowser>
{
// ...
public void Handle(OpenNewBrowser myEvent)
{
// Create your new ViewModel instance here, or obtain existing instance.
// ActivateItem(instance)
}
}
This section of the documentation will probably be useful, especially the Simple MDI section.
Additional code I mentioned in the comments:
I sometimes use a generic method along these lines ensure that if I have an existing instance of a screen of a particular type, switch to it, or create a new instance if not.
public void ActivateOrOpen<T>() where T : Screen
{
var currentItem = this.Items.FirstOrDefault(x => x.GetType() == typeof(T));
if (currentItem != null)
{
ActivateItem(currentItem);
}
else
{
ActivateItem(Activator.CreateInstance<T>());
}
}
Used like:
public void OpenBrowser()
{
this.ActivateOrOpen<BrowserViewModel>();
}
I am trying to implement MVVM for one of my Windows Phone app that i am developing and its growing to be big.
I have tried below code in Model class.I want to know how can i handle the scenario where user clicks on a button "Latest Entry" and it will connect to a service and executes a method asynchronously.Once the data is returned i have to display the latest record in UI which has 3 text fields EmpName,EmpID,Address.
Code in Model Class:
public class EmpDetailsModel:INotifyPropertyChanged
{
private string _EmpName;
public string EmpName
{
get { return _EmpName; }
set {
if (value != _EmpName)
{
_EmpName = value;
RaisePropertyChanged("EmpName");
}
}
}
private string _EmpId;
public string EmpId
{
get { return _EmpId; }
set {
if (value != _EmpId)
{
_EmpId = value;
RaisePropertyChanged("EmpId");
}
}
}
private string _Address;
public string Address
{
get { return _Address; }
set {
if (value != _EmpId)
{
_EmpId = value;
RaisePropertyChanged("Address");
}
}
}
#region myfirstmodel inotify members
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
The code to connect to service is below:
EmpAzureSer empAzureSer = new EmpAzureSer();
empAzueSer.GetLatestEntry += new GetLatestEntryCompletedEventHandler(LatestEntryCompleted);
private void LatestEntryCompleted(object sender, GetLatestEntryCompletedEventArgs e
{
//get the data from e as e.Name,e.Id and e.Address and bind them to UI.
}
view xaml code:
<Button Name="FetachLAtest" Click="FetachLatest_Click"></Button>
<TextBlock Name="EmployeeName"></TextBlock>
<TextBlock Name="EmployeeID"></TextBlock>
<TextBlock Name="EmployeeAddress"></TextBlock>
I was following the link http://msdn.microsoft.com/en-us/library/windowsphone/develop/gg521153(v=vs.105).aspx.
It was very helpful but I want to know where do i put the code to connect to service (model ? or Viewmodel ? How does the viewmodel should look like ?
There are various ways to implement MVVM into an application, it varies depending on developpers and application requirements.
But for started, let's try to keep things simple and to focus on ViewModels (because this seems to be where is your interest).
MVVM means Model View ViewModel, Model is your business/domain code, View is basically your XAML and its associated code behind, and ViewModel is the link/glue between Views and Models.
An important thing to note is that ViewModels mustn't know Views (meaning don't reference them). This ensures a better separation of concerns, and thus try to build an application easier to test and to maintain.
So to make a long story short, ViewModels don't know Views but they have to communicate with them... And this magic is made possible thanks to Bindings!
XAML/UI components display data, these data comes from the ViewModel which is bound to the View through Bindings mechanisms (provided on WP by the Silverlight framework).
This means the ViewModel contains all the data required by the View, actually a ViewModel represents all the data or behaviors of a View.
Being not the best person to describe the whole MVVM pattern and all its subtilities, i'll leave this sensitive task to most knowledgeable people in the field ;). Here are some really great links that should help you :
From Josh Smith
Wikipedia with code samples for ViewModel
If you already know MVC or MVP patterns, this one will help you to spot differences
All this being told, you must be a little bored with theory, so let's try to write some code. The problem is that there are many ways to organize your code, so all that follow is just a kind of pseudo code, it cannot be used directly into your application!
In your case, you could create just a ViewModel like this one
public class WhateverYouWantViewModel : INotifyPropertyChanged
{
private EmpDetailsModel _model;
public EmpDetailsModel Model
{
get { return _model; }
set
{
if (value != _model)
{
_model = value;
RaisePropertyChanged("Model");
}
}
}
public void GetLastestEntries()
{
// put in here the code calling your service
}
}
About assignements from data service to your this.Model, we are dealing with an asynchronous callback, so maybe it would be wiser to use the Dispatcher in case the callback is not called from the UI Thread :
EmpAzureSer empAzureSer = new EmpAzureSer();
empAzueSer.GetLatestEntry += new GetLatestEntryCompletedEventHandler(LatestEntryCompleted);
private void LatestEntryCompleted(object sender, GetLatestEntryCompletedEventArgs e
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
this.Model = new EmpDetailsModel()
{
//get the data from e as e.Name,e.Id and e.Address and bind them to UI.
};
});
}
Creating a new EmpDetailsModels before assigning it to this.Model will trigger RaisePropertyChanged and notify the View this property has changed. More specifically, the UI component bound to this property will be notified for being updated.
To bind your UI components to the ViewModel, you can do something like that :
<Button Name="FetachLAtest" Click="FetachLatest_Click"></Button>
<TextBlock Name="EmployeeName" Text="{Binding Model.EmpName}"></TextBlock>
<TextBlock Name="EmployeeID" Text="{Binding Model.EmpId}"></TextBlock>
<TextBlock Name="EmployeeAddress" Text="{Binding Model.Address}"></TextBlock>
Do not forget to set the DataContext of your View with your ViewModel instance.
Last but not least, you have to bind your "Latest Entry" Button to the ViewModel.GetLastestEntries method by calling it from your *View.FetachLatest_Click* event handler. All this can be achieved this way :
public partial class YourView : BasePage
{
private WhateverYouWantViewModel _viewModel;
public YourView()
{
InitializeComponent();
_viewModel = new WhateverYouWantViewModel();
this.DataContext = _viewModel;
}
private void FetachLatest_Click(object sender, RoutedEventArgs e)
{
_viewModel.GetLastestEntries();
}
}
And that's (almost) it! Why almost? Because the link between the View and the ViewModel is quite strong and defined into the code behind (which is something we are usually trying to avoid in MVVM).
Fortunately, there are some solutions to solve this issue :
What we call a ViewModelLocator could be used to store and to locate
ViewModels
A Command could be created in WhateverYouWantViewModel and bound to the "Lastest
Entry" Button, instead of calling directly the GetLastestEntries method in code behind
The downside of all this is that you would have to write more code and that's where MVVM framweworks come up! These frameworks will help you to write clean MVVM applications with minimum effort.
As a beginner, i would warmely advice you to visit MVVM Light Toolkit website. It contains lots of useful articles about the MVVM pattern, to learn how to design an MVVM application and to handle common scenarii using this framework. MVVM Light is not the only MVVM framework running on Windows Phone but i'm quoting it because it is widely used, it has a big community and it strives to keep things as simple as possible.
I'm aware this answer is only a starting point to achieve what you want. I only give you some ideas that need further study, but i hope it will help you move in the right direction.
I am working on a Windows Phone 7 application. Now I need to switch the view after a user tapped the designated button which takes user to another view.
Which component, theoretically, in MVVM should be in charge of the navigation, i.e. switching views? Code snippets would be good to show demonstration.
I have tried inserting the switching code in View and it works alright, but I encountered a situation where I call an asynchronous web service and would like to navigate user to the new view only after the operation is done, the navigation code should be inside the event handler.
Thank you.
P/S: My project's deadline is coming soon, I have no time to rebuild my project using MVVM tools, such as MVVM Light, Caliburn Micro, and etc.
I put a Navigate methods in the base class that all my ViewModel's share:
protected void Navigate(string address)
{
if (string.IsNullOrEmpty(address))
return;
Uri uri = new Uri(address, UriKind.Relative);
Debug.Assert(App.Current.RootVisual is PhoneApplicationFrame);
BeginInvoke(() =>
((PhoneApplicationFrame)App.Current.RootVisual).Navigate(uri));
}
protected void Navigate(string page, AppViewModel vm)
{
// this little bit adds the viewmodel to a static dictionary
// and then a reference to the key to the new page so that pages can
// be bound to arbitrary viewmodels based on runtime logic
string key = vm.GetHashCode().ToString();
ViewModelLocator.ViewModels[key] = vm;
Navigate(string.Format("{0}?vm={1}", page, key));
}
protected void GoBack()
{
var frame = (PhoneApplicationFrame)App.Current.RootVisual;
if (frame.CanGoBack)
frame.GoBack();
}
So the ViewModel base class executes the navigation if that's what you are asking. And then typically some derived ViewModel class controls the target of the navigation in response to the execution of an ICommand bound to a button or hyperlink in the View.
protected SelectableItemViewModel(T item)
{
Item = item;
SelectItemCommand = new RelayCommand(SelectItem);
}
public T Item { get; private set; }
public RelayCommand SelectItemCommand { get; private set; }
protected override void SelectItem()
{
base.SelectItem();
Navigate(Item.DetailPageName, Item);
}
So the View only knows when a navigate action is needed and the ViewModels know where to go (based on ViewModel and Model state) and how to get there.
The view should have a limited number of possible destinations. If you have to have a top-level navigation on every page, that should be part of your layout or you can put them in a child view.
I put navigation outside of MVVM in a class that is responsible for showing/hiding views.
The ViewModels use a messagebroker with weakevents to publish messages to this class.
This setup gives me most freedom and doesn't put any responsibilities in the MVVM classes that do not belong there.
It's a simple question and I searched the Internet for hours without success...
I have a model and a view model with one property. To make this property viewable in the view, I use a view-model-object which should automatically be generated from the model-object and vice versa. Of course, the following code will throw an StackOverflowException, because the updating of the model-object in the model causes an update of the view-model-object in the view-model and this causes an update of the model-object in the model and so on...
class ModelObject
{
...
}
class ViewModelObject
{
...
}
class Model : INotifyPropertyChanged
{
private ModelObject modelObject = new ModelObject();
...
public ModelObject ModelObject
{
get
{
return this.modelObject;
}
set
{
this.modelObject = value;
this.NotifyPropertyChanged("ModelObject");
}
}
}
class ViewModel : INotifyPropertyChanged
{
private ViewModelObject viewModelObject = new ViewModelObject();
private Model model = new Model();
...
public ViewModel()
{
this.model.PropertyChanged += new PropertyChangedEventHandler(this.propertyChangedEvent);
}
public ViewModelObject ViewModelObject
{
get
{
return this.viewModelObject;
}
set
{
this.viewModelObject = value;
this.model.ModelObject = new ModelObject(...);
this.NotifyPropertyChanged("ViewModelObject");
}
}
private void propertyChangedEvent(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName.Equals("ModelObject"))
{
this.ViewModelObject = new ViewModelObject(...);
}
}
}
What is the common way to synchronize these two objects?
There is no silver bullet. As model is a representation of the database and viewmodel is more closer to the interface, there is always some business logic needed to convert the model to view model and vice versa.
I usually have two methods in my view model class - SyncModel(ViewModel viewModel) and SyncViewModel(Model model)
One more suggestion -
Model should not implement INotifyPropertyChanged. The view model should implement this as its bound to the user interface. Why does the model ever need to change? It represents whats in the db. You can refresh it but why do you need change notifications for the model?
Edit: MVVM: Binding to Model while keeping Model in sync with a server version
Hard reference. Each class having a reference to another, listens to property change event and updates itself accordingly.
Observer Pattern - Have an observer class, each class register itself with an observer, observer listens for any changes and updates all its subscribers.
There's also an event aggregator which might be useful.
If you want a deferred update, an isDirty property would be required. You know your application better, google for more articles and choose wisely.