Is manipulating view objects from view models a standard in Prism projects? - c#

I have very little experience with Prism and .NET (< 1 year). Yet, I am working on a project where those technologies are used extensively. Also, I am an experienced developer, but in other frameworks, other programming languages, etc. Therefore, I have sometimes stupid questions to ask like the following one.
So, we are currently trying to build up a client application that shows a grid of data along with buttons allowing for the usual CRUD operations. The team's ansatz is the following:
We create a xaml view and define the GridControl like this:
<dxg:GridControl x:Name="MyGrid"
ItemsSource="{Binding Items}"
SelectedItems="{Binding SelectedItems}">
<dxmvvm:Interaction.Behaviors>
<dxmvvm:EventToCommand EventName="Loaded"
Command="{Binding GridLoadedCommand}"
CommandParameter="{Binding ElementName=MyGrid}" />
</dxmvvm:Interaction.Behaviors>
[...]
This triggers command GridLoadedCommand upon view loading. GridLoadedCommand stores the GridControl object in the view's data context, which is the view model.
Upon clicking the DeleteAll button, the view model's DeleteAllCommand calls a method of the following kind:
public static void DeleteAllRows(GridControl gridControl)
{
gridControl?.SelectAll();
DeleteSelectedRowsEx(gridControl);
}
In essence, that is perfectly valid code and is also working like a charm. However, in my opinion, but I might be mistaken, that kind of code goes against MVVM philosophy because in the above snippet we are clearly mixing up "view" with "view model" code. Indeed, the view model manipulates a GridControl object directly, which, as far as I know, should be avoided as much as possible, as it breaks "separation of concerns" and makes the software design entangled. Also, it might complicate unit testing a bit. Am I seeing that right or am I alien here? I would rather manipulate the ViewModel.Items and ViewModel.SelectedItems observable collections directly and trigger the relevant events to update the view instead.
Now, the actual reason why the team came up with that code is because they wanted a generic base view model class with generic CRUD operations, irrespective of what the underlying ItemsSource abd SelectedItems (see GridControl xaml code above) are. Is there a standard way to make that happen in the Prism constellation? I would just add a generic parameter to the base class with the ItemsSource's data type and pass the specific ItemsSource and SelectedItems to the generic class. Is there a better way? Is the way I've described here above with direct GridControl manipulation from the view model really the way to go?

Related

Access DataContext of Page from MainWindow (with Telerik)

I am relatively new to WPF and I have stumbled across a problem that I just can't seem to find a solution for.
I am sure that there is already a thread concerning a problem like that but in regard of my lacking knowledge it is very likely that I haven't found it or simply did not understand it.
My problem:
I am developing a WPF-application in C#. It's an Outlook-Styled application with a big MainWindow with a huge ViewModel and XAML.
What I was trying to do, is to split up the single codefiles a bit to make it a little bit more modular and compact.
I am using Telerik Controls and tried to outsource the content of single SplitContainers into Pages, which worked fine until now.
Today, a new situation came up which is somehow stupid and wasn't looking too complicated, but somehow I can't get it to work.
Situation:
I have a Treeview in my "MainWindow" and whenever I change the selection in there, I want to change a property on my Page that I have made a binding to.
So, when I click on an item in "TreeView_3" I want to set a property via EventHandler (SelectionChanged_TreeView3) on the DataContext of "Page_X".
If I had to do this on the MainWindow, I would typically do it like that:
UserViewModel uvm = mainGrid.DataContext as UserViewModel;
Then just call whatever property of specific UserViewModel (ViewModel of the MainWindow) I want to access.
I can't do this the same the same way for the page obviously since "mainGrid.DataContext" will always refer to the MainWindow, since this is where the eventhandler is called.
So what I need would be a little explanation on how to access the DataContext from a page with a different ViewModel.
If you need any code in order to explain, let me know.
You need to separate your concerns. In your code behind your should have only code that handles view related stuff. Most often my codebehind is empty.
In your ViewModels you should handle your data related logic. So instead of casting the datacontext in your code behind, handle a click with a Commandin your viewmodel.
Since there is no possibility to bind a command to the SelectedItemChanged of your TreeView you can use an interaction trigger.
<TreeView xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<i:InvokeCommandAction Command="{Binding Path=SomeCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
Ruven it is hard to say without some example code. But it could be that you need to implement INotifyPropertyChanged on the ViewModels?
https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-implement-property-change-notification
By calling OnPropertyChanged("PropertyName"); in the setter of a viewmodel property the ui will pick up the change.
Also make sure both views are referencing the same object and not copies of the same object.

How to add a MainViewModel and a MainWindowView into an own Framework? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I've made my first couple of C# .NET MVVM projects and i'd like to go on with this. So i thought it would be good to make my own simple - lets say - framework where i can put mvvm-stuff in which i need in most of my projects. I have created some controls and other helpful methods. So far so good.
Now i want to include a "generic" MainViewModel and a MainWindowView, which should give me the same surface in all of my projects into my Framework and i don't know whats the best way to do this.
This MainViewModel should be the basis for the other projects. I have declared a ribbon-menue with buttons i always need (like show, edit, save settings) and i have a method in it where i can add buttons into the ribbon-menue of my view with just one method call (AddButton(Command, Image, Label)), a command for opening a tabcontrol, a ReloadCommand, Fields to Repositories, a DialogService and methods to register workspaces in this ViewModel.
I also have a MainWindowView where i have my basic UI with a RibbonMenue, a StatusBar, ComboBoxes on the left and i just want to add application-specific TabItems!?
I don't really know whats the best way to "specify" this in the special application which uses the framework. I just thougt of Inheritance, or Reflection with Attributes or something like this.
What do would be the best way to use a MainViewModel and a MainWindowView in a framework?
I'm not exactly sure if we're on the same page, but I'm assuming that your MainViewModel class is like a 'base view model' class. I have a generic BaseViewModel class in my MVVM projects, but I also have generic BaseDataType classes as well that (both) expose the INotifyPropertyChanged interface to the extending classes.
In my applications, I have a series of Manager classes that implement the Singleton pattern (eg. there can be only one of each). The BaseViewModel class exposes these valuable manager classes to the extending view model classes. Each manager class provides some further functionality. For example, see the following list:
StateManager: maintains global data/object state across the whole application
DependencyManager: maintains dependency with a collection of interfaces and their concrete implementations
FeedbackManager: maintains access to the application feedback control (for user feedback)
WindowManager: provides access to file dialogs and child window management
ClipboardManager: provides access to the computer clipboard
UiThreadManager: provides access to multi-threading
EmailManager: provide access to be able to send e-mails
HardDriveManager: provides access to the user's computer hard drives
ExportManager: provides access to XML generation and FTP transfers
DataOperationManager: provides access to all data operations (explained further below)
UpdateManager: provides access to application updates
SecurityManger: provides access to all security matters
ExcelManager: provides access to functionality that generates Excel documents based on view model data.
All of these manager classes are accessible from any view model that extends the BaseViewModel class.
In addition to this, my (abstract) BaseViewModel also exposes certain Command objects that are required in every view, like 'Save', Delete', 'Refresh' etc.
Finally, it also provides access to often used functionality like 'InsertNewDataTypeToCollection' and 'RemoveDataTypeFromCollection' methods.
As well as this part of the 'framework', I also have a number of base data type classes. These provide common properties and often used functionality like data synchronisation, animation, data error reporting (an extension of the 'IDataErrorInfo' interface) which automatically links in with the feedback control.
The final part of my system revolves around database access. I have a suite of classes that I wrap around every data object that comes or goes to the database. These automatically provide user feedback in the UI, asynchronous operations, and error logging and handling.
I hope that this helps you and that I didn't misunderstand your question.
UPDATE >>>
Oooops, I forgot to mention the most important part... I have a MainViewModel class that extends BaseViewModel and is displayed in the MainWindow.xaml. In this view model, there is a public property of type BaseViewModel:
public BaseViewModel ViewModel
{
get { return viewModel; }
set
{
if (viewModel != value)
{
viewModel = value;
NotifyPropertyChanged("ViewModel");
}
}
}
I can set this property to any view model class that has extended the BaseViewModel class. In MainWindow.xaml, I have the following setup:
...
<Grid Grid.Row="1" Background="{StaticResource Windows7LightBackground}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentControl Grid.RowSpan="2" Content="{Binding ViewModel}" Margin="5" />
</Grid>
<Controls:FeedbackControl Grid.Row="0" Feedback="{Binding FeedbackManager.Feedback}"
VerticalAlignment="Top" HorizontalAlignment="Stretch" MaxWidth="750"
Margin="100,22,100,0" />
...
In the first Grid row, I have a Ribbon control, in the second I have a ContentControl that displays the view that matches the view model that is set in the ViewModel property and then I have a custom FeedbackControl that slides in and out of view when feedback arrives.
The final piece of this puzzle is linking the views with the view models. This is done in the App.xaml file using DataTemplate objects:
...
<DataTemplate DataType="{x:Type ViewModels:HomeViewModel}">
<Views:HomeView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:MainViewModel}">
<Views:MainView />
</DataTemplate>
...

When to use event and command for WPF/MVVM?

I am practicing on how to write a WPF application with MVVM pattern. So far I haven't used command in my code. In my Viewmodel I implement INotifyPropertyChanged and used (event PropertyChangedEventHandler PropertyChanged) to fire events.
Why do I feel like I still miss some concept of WPF about how to use command?
When is it appropriate to use commands?
Commands in WPF are used to abstract an user-triggered action (such as clicking a Button or pressing a key.
here's a basic example:
Suppose you want to search for employees in your database when the user clicks the "Search" button, or hits the enter key while focusing the Search Box.
You might define your ViewModel like this:
public class MyViewModel: ViewModelBase
{
public string SearchText {get;set;} //NotifyPropertyChanged, etc.
public Command SearchCommand {get;set;}
public MyViewModel()
{
//Instantiate command
SearchCommand = new DelegateCommand(OnSearch);
}
private void OnSearch()
{
//... Execute search based on SearchText
}
}
And your View:
<StackPanel>
<TextBox Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding SearchCommand}"/>
</TextBox.InputBindings>
</TextBox>
<Button Content="Search" Command="{Binding SearchCommand}"/>
</StackPanel>
Notice how the KeyBinding and the Button's Command property are both bound to the same Command (SearchCommand) in the ViewModel. This facilitates reutilization, and also helps keep actual logic in the ViewModel, with all its goodness (testability, etc), while keeping the view clean and code-less.
The fun thing is that using original Commands concept from WPF is absolutely not required :). You could build large and complex applications with all that beauty of loosely coupled design (xaml) and business logic (c#/vb code) in place with just using MVVM all around and free open source application framework library Caliburn.Micro.
Disclaimer: I'm just a happy user of this library and have nothing to do with its creators, so this is not paid ads or something like that.
Please, just take a look over this very basic sample from official documentation:
--> Basic Configuration, Actions and Conventions <--
and you will fill the power of binding events from you XAML view directly to methods in your C# view-model without mess of proxy code for commands declaration and registration (like this is implemented in other similar application frameworks).
And never mind that this sample is Silverligh app - Caliburn.Micro support all major Xaml platforms almost the same way and the WPF sample will looks pretty like above Silverlight-based.
In addition to the mentioned major capability (buinding to methods) Caliburn.Micro have:
handy predefined naming conventions for binding that leaves your XAML files clean and readable (and yet still design-time friendly!)
base implementation of INotifyPropertyChanged so that you could just inherit from it all of your view-models
base classed for implementation of frequently used scenarios like:
master-details
parent-child
list-with-selected-items
EventAggregator for even more loosely coupled communication between view-models and other classes
loosely coupled support for things like keyboard focus and windows management (for WPF)
and a bit more :)
Just give it the chance and you will never need vanilla WPF Commands ;)

MVVM and View/ViewModel hierarchy

I'm working on making my first game using C# and XAML for Windows 8. I'm still learning the core concepts and best practices, and MVVM has been a hurdle. I'll attempt to ask the question in two parts.
Background
The game I'm making is Sudoku. Sudoku has a board that contains a 9x9 grid of tiles. I have three models - Game, Board, and Tile. When a Game is created, it automatically creates a Board, and when the Board is created, it creates 81 (9x9) Tiles.
1. With a hierarchy of views, how are corresponding view models created?
To match the hierarchy of models, I would like to have a hierarchy of views (GameView contains a BoardView which contains 81 TileViews). In XAML, it's pretty easy to create this hierarchy of views with user controls, but I don't understand how the view models get created.
In the examples I've seen, the data context of a user control is often set to the view model (using the ViewModelLocator as a source) which creates a fresh instance of the view model. This seems to work well if you have a flat view, but also seems like it gets messy when you have a hierarchy. Does the GameView create a GameViewModel and leave it up to its BoardView child to create a BoardViewModel? If so, how does the GameViewModel communicate with the BoardViewModel? Can the BoardViewModel communicate back up the hierarchy to the GameViewModel?
2. How does a view model get model data?
In iOS, I would start by using a service to fetch a Game model that was pre-populated with data. I would then create a GameViewController view controller (which was in charge of creating the view) and pass the Game to it. In MVVM, I see the value in having a view be in charge of creating its own view model (ideally using a ViewModelLocator), but I don't understand how that view model gets the model.
In all of the examples I've found online, the view model uses some service to fetch its own data. But I haven't come across any example that accepts constructor params or params passed from a higher level of navigation. How is this done?
I don't want to use an application resource or some other kind of singleton storage method for my model because, not that I do, but what if I wanted to display multiple puzzles on the screen at once? Each GameView should contain its own Game.
Not only does the GameViewModel need a reference to the Game model, but the BoardViewModel that was created somehow (see question 1) needs a reference to the Board model that belongs to the Game model. The same goes for all the Tiles. How is all this information passed down the chain? Can I do this much heavy lifting entirely within XAML, or am I going to have to do some sort of binding or other initialization in code?
Phew!
I appreciate any advice you can give, even if it's not a full answer. I'm also keen to find any examples of MVVM projects that share similar challenges to my own. Thanks a ton!
I would start by creating a class to begin the application with. Typically I call that class something like ApplicationViewModel or ShellViewModel, even though technically it can abide by different rules than what I would typically use for a ViewModel
This class gets instantiated at startup, and is the DataContext for the ShellView or ApplicationView
// App.xaml.cs
private void OnStartup(object sender, StartupEventArgs e)
{
var shellVM = new ShellViewModel();
var shellView = new ShellView();
shellView.DataContext = shellVM;
shellView.Show();
}
This is usually the only place I set a DataContext for a UI component directly. From this point on, your ViewModels are the application. Its important to keep this in mind when working with MVVM. Your Views are simply a user friendly interface that allows users to interact with the ViewModels. They're not actually considered part of the application code.
For example, your ShellViewModel may contain:
BoardViewModel CurrentBoard
UserViewModel CurrentUser
ICommand NewGameCommand
ICommand ExitCommand
and your ShellView might contain something like this:
<DockPanel>
<Button Command="{Binding NewGameCommand}"
Content="New Game" DockPanel.Dock="Top" />
<ContentControl Content="{Binding CurrentBoard}" />
</DockPanel>
This will actually render your BoardViewModel object into the UI as the ContentControl.Content. To specify how to draw your BoardViewModel, you can either specify a DataTemplate in ContentControl.ContentTemplate, or use implicit DataTemplates.
An implicit DataTemplate is simply a DataTemplate for a class that doesn't have an x:Key associated with it. WPF will use this template anytime it encounters an object of the specified class in the UI.
So using
<Window.Resources>
<DataTemplate DataType="{x:Type local:BoardViewModel}">
<local:BoardView />
</DataTemplate>
</Window.Resources>
will mean that instead of drawing
<ContentControl>
BoardViewModel
</ContentControl>
it will draw
<ContentControl>
<local:BoardView />
</ContentControl>
Now the BoardView could contain something like
<ItemsControl ItemsSource="{Binding Squares}">
<ItemsControl.ItemTemplate>
<ItemsPanelTemplate>
<UniformGrid Rows="3" Columns="3" />
</ItemsPanelTemplate>
<ItemsControl.ItemTemplate>
</ItemsControl>
and it would draw a board using a 3x3 UniformGrid, with each cell containing the contents of your Squares array. If your BoardViewModel.Squares property happened to be an array of TileModel objects, then each grid cell would contain a TileModel, and you could again use an implicit DataTemplate to tell WPF how to draw each TileModel
Now as for how your ViewModel gets its actual data objects, that's up to you. I prefer to abstract all data access behind a class such as a Repository, and have my ViewModel simply call something like SodokuRepository.GetSavedGame(gameId);. It makes the application easy to test and maintain.
However you get your data, keep in mind that the ViewModel and Models are your application, so they should be responsible for getting data. Don't do that in the View. Personally I like keeping my Model layer for plain objects that hold data only, so only ever perform data access operations from my ViewModels.
For communication between ViewModels, I actually have an article on my blog about that. To summarize, use a messaging system such as Microsoft Prism's EventAggregator or MVVM Light's Messenger. They work like a kind of paging system: any class can subscribe to receive messages of a specific type, and any class can broadcast messages.
For example, your ShellViewModel might subscribe to receive ExitProgram messages and close the application when it hears one, and you can broadcast an ExitProgram message from anywhere in your application.
I suppose another method would be to just attach handlers from one class to another, such as calling CurrentBoardViewModel.ExitCommand += Exit; from the ShellViewModel, but I find that messy and prefer using a messaging system.
Anyways, I hope that answers some of your questions and will point you in the right direction. Goodluck with your project :)

MVVM Light - Multiple ViewModels (and connecting them up)

I am trying to learn the MVVM pattern (C#), having come from a Windows Forms background. I am using the MVVM Light toolkit, and so far I think it is brilliant.
I have made several small applications, however one thing I am struggling with is introducing a second view.
I want to (for example), have a button on my MainViewModel, which via a RelayCommand, opens up a new Window - let's say an "About" window. I have done hours of research on the web for this however it seems I can't get my AboutViewModel to communicate with/show my AboutView.
I have placed a receiving messenger in the code-behind constructor of the AboutView.xaml - however I can't get it to receive any messages from the AboutViewModel, and thus can't make it 'Show()'.
If anyone has an example of an Mvvm Light WPF app using multiple views that would be great :)
There are two ways I can think to do this easily
The first would be to use a Popup instead of a new Window. For example, I often put properties in my ViewModel for PopupContent and IsPopupVisible, and set those values anytime I want to display my Popup control. For example, a ShowAboutPopup relay command might run something like this:
void ShowAboutPopup()
{
PopupContent = new AboutViewModel();
IsPopupVisible = true;
}
You can display it using a Popup object, or a custom UserControl. I prefer to use my own custom Popup UserControl, which will usually end up looking like this:
<Window>
<Canvas x:Name="RootPanel">
<SomePanel>
<!-- Regular content goes here -->
</SomePanel>
<local:PopupPanel Content="{Binding PopupContent}"
local:PopupPanel.IsPopupVisible="{Binding IsPopupVisible}"
local:PopupPanel.PopupParent="{Binding ElementName=RootPanel}" />
</Canvas>
</Window>
The PopupContent property is a ViewModel (such as an AboutViewModel), and DataTemplates are used to tell WPF to draw specific ViewModels with specific Views
<Window.Resources>
<DataTemplate DataType="{x:Type local:AboutViewModel}">
<local:AboutView />
</DataTemplate>
</Window.Resources>
The other method is to have some kind of ApplicationViewModel that runs on startup, and is responsible for the overall application state, which includes which window(s) are open.
Typically I prefer to have a single ApplicationView that contains a ContentControl to display the current page
<Window>
<ContentControl Content="{Binding CurrentViewModel}" />
</Window>
however it can also be used to manage multiple windows. If you do use it to manage multiple Window objects, be warned that this will not be a pure ViewModel because it will need to access some View-specific objects, and referencing UI objects it not something a ViewModel should do. For example, it may subscribe to receive ShowWindow messages, and upon receiving those messages it would create the specified View and show it, and possibly hide the current window as well.
Personally, I try to avoid multiple windows as much as possible. My usual method is to have a single View that contains consistent application objects for any page, and a ContentControl containing dynamic content that changes. I have an example using this navigation style on my blog if you're interested
As i can see you want a navigation in your MVVM app?
Word goes to the creator of MVVM Light - Laurent Bugnion - with his post about using Navigation Service for switching Views. It's actually about Windows Phone & Silverlight but same should apply to WPF.
Also this answer in related question uses this approach.

Categories