WinForms - Make a Property Bindable in Data Sources Explorer - winforms

I have a couple of ViewModel classes I have written for my WinForms application. One is a parent view model, the other is a child view model.
public class EditDrawingViewModel : SecureEntityViewModel
{
public DrawingChildViewModel ChildViewModel { get; private set; }
}
In my form I have dropped a BindingSource in the Designer, and set its DataSource property to a new Project Data Source of type EditDrawingViewModel.
I want to set a binding to something else to the DrawingChildViewModel property of the main view model.
So say a new BindingSource named DrawingVMBindingSource. I want to set it's DataSource to EditDrawingViewModel.ChildViewModel. However, the property does not show in the Data Source explorer - I only get List implementations.
So in the above, Materials, DrawingAreas, DrawingApplications are lists. Nothing else shows up. I would like to see ChildViewModel but I am not sure how.

To create the object data source:
Build your project.
Note:
You must build the project before objects in the project can be selected in the Data Source Configuration Wizard.
Click Add New Data Source in the Data Sources window.
The Data Source Configuration Wizard starts.
On the Choose a Data Source Type page, select Object, and then click Next.
On the Select the Data Objects page, expand the namespace nodes and select the check box next to the class you want to create the datasource from.
Click Finish.
The chosen object appears in the Data Sources window.

Related

What should compose View with ViewModel and show result?

I have problem of thinking ideal solution for creating and showing window in WPF MVVM application. Some part of application needs to show some window with some data. I create VM, set its properties, create View, assign its VM (in constructor), then display window. This is done using class that I named ViewController and this class have methods with parameters for every window in my application. I think there can be better solution than this, but not overengineered.
The normal solution is you have a class that wraps and instantiates a View ViewModel pair. This is often called screen. it would look something like this.
public class Screen<TView> where TView : Window
{
public Screen(TView view, object viewModel){
//store view and viewModel props
//display view
//set viewModel as DataContext of view
}
}
This is a very rough example, there are lots of ways you can do it.
In the last I created implementation of IWindowManager, which have methods for showing required windows and these methods have parameters if needed. Methods create view model, set its properties and inject it to window. Only drawback of this solution is when new window is needed, new method must be added to interface and implementation of WindowManager.

Caliburn Micro - ActivateItem using Container

I was going through the Caliburn Micro documenation here. Simultaneously, I was trying to put up some rough code for experiment. I am a little confused about how to activate item using a container and how to pass an object to the ViewModel that we are activating.
Lets consider a master/detail scenario. The master contains a list (say datagrid) and the details contain specific row from the master for update(say tab item inside tab control). In the documentation (for ease of understanding), I believe the detail ViewModel was directly instantiated using code like this
public class ShellViewModel : Conductor<IScreen>.Collection.OneActive {
int count = 1;
public void OpenTab() {
ActivateItem(new TabViewModel {
DisplayName = "Tab " + count++
});
}
}
So, to apply the above fundamental concept in real world app, we need to instantiate the DetailViewModel (TabViewModel above) using container(say MEF). The challenge then is to know whether the particular DetailViewModel is already opened in the TAB Control. The immediate crude thing that came to my mind was maintaining a List of the Opened Tabs (DetailViewModels). But then we are again referencing DetailViewModel in the MasterViewModel defeating the purpose. Is there any options available to solve this issue.
The second thing that is troubling me is how to pass the Objects from MasterViewModel (Selected Detail Item) to the DetailViewModel. If we use the EventAggregator here then each of the opened DetailViewModels will receive the event which I am not sure how to handle.
If anyone can throw some light on the above two issues, I would be grateful
Update:
The Master is Conductor like this
public class MainViewModel : Conductor<IScreen>.Collection.OneActive, IShell {
....
}
And the detail is defined like this
public class TabViewModel : Screen {
....
}
Both are in the same Window.
I'm not sure exactly what the issue is. In your conductor of many, you have an Items collection provided by Caliburn.Micro. When you come to display a detail view, you can check this collection for the existence of that detail view (using the primary key which you have from the master view).
If the item is already in the Items collection then just activate it (using the ActivateItem method). If the item isn't in the collection, then instantiate it (presumably using a factory if you're using MEF), and add it to the Items collection, and then activate it.

Reverting an object is a user clicks "Cancel" in WPF

I have a Window that serves as a dialog in a WPF application. This dialog has an "OK" and a "Cancel" button. I am setting the DataContext of the Window to an instance of an object in my application. The user can change the values of the properties of the object within the Window. If a user clicks "Cancel", I want to revert the property values back to their original values. Is there an easy way to do this in WPF?
For instance, I know with RIA data services there is RejectChanges. Is there something similar on the client-side with WPF?
Thanks!
In object which is set to DataContext (ideally it should be ViewModel in MVVM approach) expose two commands
public ICommand CancelCommand { get; set; }
public ICommand OkCommand { get; set; }
Then for the buttons assign these commands like shown below
<Button Command="{Binding CancelCommand}" ... />
You've to keep two copies of object, a copy should be created by Deep Copy or if an object has a few editable fields you can keep those as class fields. Basically on initialization stage do backup editable object properties, then bind to DataContext editable version of object. In Cancel Command handler - restore from a backup copy...
When the object is simple (just a few properties of basic types such as string, int, etc.) DeepCopy or IEditableObject is a very good option.
When the object is a node in a more complex hierarchy this might prove to be too difficult and going back to the server/model and reloading the original data is much easier.

wpf mvvm passing parameters between viewmodels using commands

This is my first attempt at MVVM. My application's core is loosely based Josh Smith's msdn article. And I am also using the mvvm light framework.
I have a main window containing a command list area and a workspace area which shows usercontrols/views as tabitems, each usercontrol has a corresponding viewmodel. The mainWindow also has a viewmodel containing my command list, and the workspace viewmodels have a base workspace viewmodel.
My default view has a master datagrid, of MappingSets, that can have one selected item. The commands launch new tabitems with views that handle MappingSet detail based on that selected item. I have a View/ViewModel that, depending on the command used should return either a tabitem for creating a new MappingSet with no existing data, or a tabitem containing the detail of the selected item for editing, or a tabitem containing detail the selected item as the base for a new MappingSet.
Having Set the scene, what I have not managed to work out is command dependent way to pass parameters, such as the identifier of the selected MappingSet object, to instantiate my viewmodel in one of the three states mentioned above? For instance would the mvvmlight messenger be appropriate for this task?
This is a perfect scenario for the messenger/eventaggregator. However, your message chain might be a bit convoluted. From what I'm understanding, your Main window holds a list of commands (like a menu or a ribbon). Here is how I see the chain of events.
You select a MappingSet from the datagrid, this causes a MappingSetSelected message to be fired (with a payload of the selected MappingSet)
The main window listens for that message and stores the currently selected MappingSet
When the user clicks the button a "EditMappingSet" or "CreateNewMappingSet" message is fired (or if the Window is responsible for creating the new views, it creates them itself).
If there are only three options, you could have them binding to three different commands and within the commands do the passing of your self-defined variable.
private RelayCommand _openMappingSetCommand;
//Command that one of your options is bound to
public ICommand ViewMappingSetOption1
{
get
{
if (_openMappingSetCommand == null)
{
_openMappingSetCommand = new RelayCommand(param => this.DoTabRequest("your parameter");
}
return _openMappingSetCommand ;
}
}
// Method that creates your viewmodel
private void DoTabRequest(parameterType parameter)
{
WorkspaceViewModel viewModel = null;
if (viewModel == null)
{
viewModel = (WorkspaceViewModel)Activator.CreateInstance(typeof (viewModelType), parameter);
this.Workspaces.Add(viewModel);
}
this.ActiveWorkspace = viewModel;
}
Then allow for that parameter on the constructor of your viewmodel and do whatever else you need based on that.

Make a Dialog ViewModel binding ready, call Dialog and return data from it in MVVM

Do you see a better way how I can call/contstruct a Dialog from a Controller/ViewModel return data from it and set the DocumentViewModel as DataContext of the Dialog?
The problem is I can not use View first approach in the DocumentDetailWindow and its belonging UserControl because I can not set the Model to the DocumentViewModel`s Document Property in XAML!
How would you solve that scenario? Make Dialog properly bindable, call dialog and return data from it to the LessonPlannerController so the new Document can be saved on database and added to the bound ObservableCollection of Documents so the GUI is refreshed with one more Document.
LessonPlannerController/ViewModel:
private void OnAddDocument()
{
DocumentDetailWindowaddDocumentWindow = new DocumentDetailWindow();
DocumentViewModeldocumentViewModel = new DocumentViewModel();
documentViewModel.Document = new Document();
documentViewModel.Repository = new LessonPlannerRepository();
documentViewModel.SaveDocumentDelegate += new Action<Document>(OnSaveDocument);
addDocumentWindow.DataContext = documentViewModel;
addDocumentWindow.ShowDialog();
}
UPDATE:
I have even thought about not making this => documentViewModel.Document = new Document();
because why do I need a Model in a in a ViewModel when I can just do this:
IN REALITY those properties have a NotifyPropertyChange...
public string DocumentName {get;set;}
public string Keywords {get;set;}
then I could create a Document instance with the above properties in the DocumentViewModel, when the Save command is executed and then pass the Document via Callback to the LessonPlannerControl etc... it seems View first is not working when you have to subscribe your event to a method. Only ViewModel first works then.
What do you think? Should I not use ocumentViewModel.Document = new Document();
and create those 2 properties in the DocumentViewModel. Hm... but why recreate if they are already in the Document Model?...
Do these answer your question?
WPF MVVM dialog example
or
http://www.codeproject.com/KB/architecture/MVVM_Dialogs.aspx

Resources