I have made an application which showns a lists of client. You can open a client, and the client's details are shown.
My application takes quite a long time to start, so I want to improve the startup performance.
In pseude-code, my main window looks like this
<Window>
<c:WelcomeAnimation Visibility="Visible" />
<c:ClientList Visibility="Collapsed" />
<c:ClientDetails Visibility="Collapsed" />
</Window>
Now, before the main window is shown, I see that the ClientList and ClientDetails are intialized. This is time consuming, so I want to delay this initialization and do it when the main window is shown and the WelcomeAnimation is running.
This will give at least the perception that the application starts faster.
Question: What are my options in window design. I like to have the above XAML view. I can of course do everything in code-behind, so my main window XAML will be nothing more than
<Window />
but maybe there are better options I'm not aware of?
This depends. When the startup time is because of code you have written yourself (e.g. calling web services or fetching data from the database), don't execute that code on initialize, but fire off a background thread/ThreadPool task and run the code there.
When the startup time is actually just because of the control being loaded (e.g. it is a very complex control with many visuals), you have two options. Either put in a replacement panel instead of the control and fill that once the animation is displayed. The second option is to just bite the bullet.
One more thing to note. If the startup times actually are because of a huge amount of visuals, the initialization will have to be done on the UI thread anyway, so the animation will not be playing while loading the control.
Related
I am completely new to MVVM and I am creating an UWP app for keeping track of my software development, I am still learning.
So what I want to make is:
An app that contains single page ->
In MainPage.xaml I have something like this:
<!--MainPage Content-->
<Grid>
<!--For SearchBox-->
<AutoSuggestBox x:Name="SearchBox"/>
<!--For Adding Item-->
<AppBarButton x:Name="AddAppButton"/>
<!--Listview that contains main data-->
<ListView x:Name="AppsListView"/>
<!--This is DataTemplate of listview-->
<DataTemplate>
<Grid>
<!--Icon of App-->
<Image/>
<!--Name of App-->
<TextBlock/>
<!--For Editing Item-->
<AppBarButton/>
<!--For Deleting Item-->
<AppBarButton/>
</Grid>
</DataTemplate>
</Grid>
In Model I have something like this:
public class DevApp
{
public string name { get; set; } // For App Name
public string Iconsource { get; set; } // For App Icon
public ICommand EditCommand; // For Edit AppBarButton
public ICommand DeleteCommand; // For Delete AppBarButton
}
In ViewModel, something like :
public class ViewModel
{
// For ItemSource of ListView
public ObservableCollection<DevApp> DevApps = new ObservableCollection<DevApp>();
// For Add AppBarButton
public ICommand AddCommand;
}
Now this is me first time trying to create a neat and clean Mvvm app.
Now I have this question:
I know how to bind command to button or AppBarButton but how am I supposed to bind a Methods of a Xaml Control such as Listview's SelectionChanged() or AutoSuggestBox's TextChanged() Methods to ViewModel ?
How can I Load Data from save file ? As there is no InitializeComponent() in ViewModel like in CodeBehind to start from, where shall I pull LoadData() method which loads data to ListView ? ( my viewmodel is bind to view using <MainPage.DataContext> and I wanna keep code behind completely empty. )
Where shall I put Data class that can manage load save and edit data to savefile.
How shall I distribute responsibilities among classes ?
I have seen people using mvvm and they create files like:
services, helpers, contracts, behaviours, etc.
and I have seen same thing in Windows Community Toolkit Sample App
Is it required for Mvvm.
And what are services and helpers.
Shall I really use Mvvm for this ?
I tried using Mvvm in this just for curiosity but like
ITS BEEN 1 MONTH I AM MAKKING THIS APP! but it gets messed up again and again,
If I used Code Behind it would have been done in few days.
BY time now I realize that Mvvm is good at data bind in complex apps but
When it comes to simple things like a simple app with listview, I think code-behind
is better and it keeps things simple.
Please answer these questions I am really struggling in making this app.
I know how to bind command to button or AppBarButton but how am I supposed to bind a Methods of a Xaml Control such as Listview's SelectionChanged() or AutoSuggestBox's TextChanged() Methods to ViewModel
You could bind SelectionChanged with command by using Xaml Behavior InvokeCommandAction, or using x:bind markup extension to bind a method, for more please refer to this link.
How can I Load Data from save file ? As there is no InitializeComponent() in ViewModel like in CodeBehind to start from, where shall I pull LoadData() method which loads data to ListView ? ( my viewmodel is bind to view using <MainPage.DataContext> and I wanna keep code behind completely empty. )
Base on the first question, you could detect Page Loaded event and Invoke CommandAction where in the ViewModel. Then loading the file in the viewmodel LoadedCommand.
<i:Interaction.Behaviors>
<ic:EventTriggerBehavior EventName="Loaded">
<ic:InvokeCommandAction Command="{x:Bind ViewModel.LoadedCommand}" />
</ic:EventTriggerBehavior>
</i:Interaction.Behaviors>
Where shall I put Data class that can manage load save and edit data to savefile
The better place that savefile is current app's local folder, and it have full access permission, please refer to Work with files document.
How shall I distribute responsibilities among classes ?
I have seen people using mvvm and they create files like:
services, helpers, contracts, behaviours, etc.
and I have seen same thing in Windows Community Toolkit Sample App Is it required for Mvvm. And what are services and helpers.
For mvvm design, model view viewmodel are necessary. And it is not necessary to make services, helpers, contracts, behaviours, it should base on your design. For example if you want to make NavigateService, you need make static service class to manager current app's navigation. We suggest you make sample project with TempleStudio that contains some base service and behaviors.
Shall I really use Mvvm for this ?
I tried using Mvvm in this just for curiosity but like
ITS BEEN 1 MONTH I AM MAKKING THIS APP! but it gets messed up again and again,
If I used Code Behind it would have been done in few days. BY time now I realize that Mvvm is good at data bind in complex apps but
When it comes to simple things like a simple app with listview, I think code-behind
is better and it keeps things simple.
Your understanding is correct, But Decoupling(mvvm) your code has many benefits, including:
Enabling an iterative, exploratory coding style. Change that is isolated is less risky and easier to experiment with.
Simplifying unit testing. Code units that are isolated from one another can be tested individually and outside of production environments.
Supporting team collaboration. Decoupled code that adheres to well-designed interfaces can be developed by separate individuals or teams, and integrated later.
Improving maintainability. Fixing bugs in decoupled code is less likely to cause regressions in other code.
In contrast with MVVM, an app with a more conventional "code-behind" structure typically uses data binding for display-only data, and responds to user input by directly handling events exposed by controls. The event handlers are implemented in code-behind files (such as MainPage.xaml.cs), and are often tightly coupled to the controls, typically containing code that manipulates the UI directly. This makes it difficult or impossible to replace a control without having to update the event handling code. With this architecture, code-behind files often accumulate code that isn't directly related to the UI, such as database-access code, which ends up being duplicated and modified for use with other pages.
I wonder if that would break the MVVM pattern and, if so, why and why is it so bad?
WPF:
<Button Click="Button_Click" />
Code Behind:
private void Button_Click(object sender, RoutedEventArgs e)
{
ViewModel.CallMethod();
}
View Model:
public void CallMethod()
{
// Some code
}
IMHO, it keeps the code behind quite simple, the view model is still agnostic about the view and code behind and a change to the view doesn't affect the business logic.
It seems to me more simple and clear than Commands or CallMethodAction.
I don't want the kind of answer "it is not how it should be done". I need a proper and logical reason of why doing so could lead to maintenance or comprehension problems.
Nope, this is perfectly fine.
It's the View's job to handle user input and interact with the ViewModel. A button click event-handler, which calls a method of the ViewModel in response, falls quite cleanly into this role.
What you have posted is clean, readable, efficient, maintainable, and fully in the spirit of the MVVM design pattern.
Now, in a more general sense, what you really want to ask is: "why choose ICommands, vs Event Handlers for MVVM?" Well, you certainly wouldn't be | the | first.
No, it doesn't break MVVM, as long as you don't introduce logic that more appropriately belongs in the viewmodel.
It has the potential to reduce the clarity, IMO, because it breaks the view into XAML and c# files that are tightly coupled and where you can't see everything going on in one place. I find it easier to have zero code behind because it means less context switching when working on the view.
It can also make it more challenging to work in an environment where your UI designer isn't a C# programmer, because then two different people are maintaining the tightly-coupled files.
Edit
Here's an example of what I mean. This is from a weekend project I did to implement Minesweeper in WPF for fun and experience. One of my biggest WPF challenges was mouse input. For anyone who hasn't wasted time on the game before, the left mouse click reveals a cell, the right mouse button toggles a flag on the cell, and the middle mouse button will (conditionally) reveal adjacent cells.
I first started by considering using System.Windows.Interactivity's EventTrigger along with InvokeCommandAction to map events to commands. This sort-of worked for the right mouse button (wasn't a true click event, but a MouseRightButtonUp) but it wouldn't work at all for the middle mouse button which had no specific actions, only the generic MouseDown/MouseUp. I briefly considered prism's variation on InvokeCommandAction which could pass the MouseButtonEventArgs to its handler, but that very much broke the MVVM concept and I quickly discarded it.
I didn't like the idea of directly putting event handlers in the code-behind because that tightly coupled the action (the mouse click) and the response (revealing cells, etc.). It also wasn't a very reusable solution - every time I wanted to handle a middle click I'd be copying, pasting, and editing.
What I settled on was this:
<i:Interaction.Triggers>
<mu:MouseTrigger MouseButton="Middle" MouseAction="Click">
<i:InvokeCommandAction Command="{Binding Path=RevealAdjacentCells}" />
</mu:MouseTrigger>
</i:Interaction.Triggers>
In this case, there's no code in the code behind. I moved it into a MouseTrigger class I created that inherits from System.Windows.Interactivity.TriggerBase which, while being view-layer code, isn't part of any specific view, but a class which any view could utilize. This handler code is as agnostic as possible as to what kind of element it's attached to - anything derived from UIElement will work.
By leveraging this approach, I gained two key things over doing this in the event handlers on the code-behind:
There's a loose coupling between the event and the action. If I had a UXD working on the UI, they could change what mouse button the command was associated to by just editing a line of XAML. For example, swapping right and middle mouse buttons is trivial and requires no .cs changes.
It's reusable on any UIElement, not tied to any particular one. I can pull this out anytime I need to solve this kind of problem in the future.
The main drawback here is that it was initially more work to set up. My MouseTrigger class is more complex than the event handlers by themselves would be (mainly around properly handling dependency properties & changes thereof). XAML can also often be rather verbose for something that would seem simple.
I've been researching MVVM and WPF for a few weeks now, as I'm putting together a UI for an Application that another developer is doing the backend for. I don't have tons of GUI experience, so I'm just trying to figure it out as I go along.
I'm starting to understand the concept of keeping the backend code separate from the UI, but I can only find simple, one Window examples of MVVM online.
The application I'm designing is a Kiosk that moves step-by-step through a series of screens based on user input and scans. What is a good way to separate and design these transitions?
For example, I have a welcome screen that waits for the user to scan their ID. Once it gets their ID, it shows a new Window, or View, or whatever you want to call it, asking the user to confirm the scanned information and push the continue button.
Then it moves to a new screen where the user makes selections and so on until, and after a couple more "screens", the result is printed and it resets for the next user.
Are there any good implementation examples of this on the web?
EDIT: The application is full screen. My first instinct was to just design each screen as a separate window and Show() them one after the other, but this seems sloppy and I'm guessing it's not the best way.
Another thing I tried was to make each individual view a UserControl and load them in one main panel, one after the other based on the step. Once again, not sure this is the best method.
Add a Content Control in your MainView like below,
<ContentControl Content="{Binding CurrentView}"/>
Create DataTemplates for your different Views like below,
<DataTemplate x:Key="Viewer" DataType="{x:Type VM:TiffImageViewerViewModel}">//ViewModel Name
<view:TiffViewer/>//View Name
</DataTemplate>
MainViewModel
public object CurrentView { get; set; }
private TiffImageViewerViewModel _TiffImageViewerViewModel;
public TiffImageViewerViewModel TiffImageViewerViewModel
{
get
{
return _TiffImageViewerViewModel;
}
set
{
_TiffImageViewerViewModel = value;
}
}
Create the object and assign it to CurrentView.
This link gives more clarity
I'm working on an application, and I'm using the MVVM approach.
Basically, there are currently two Pages, and 1 MainWindow.
I switch between the pages using a Frame inside MainWindow.
In the main window, there are 2 buttons which are basically global and should show in all pages; x (exit) and settings.
This is basically my 'shell', as I decided to not use a window border.
The problem is I'd like each page to have a different background and this is where it gets complicated:
- Settings page: Grey background.
- Main Page: Rotating background color that changes according to a property.
The thing is the background is being set in the main window, because it should apply to the global area as well (the top, where the exit and settings buttons are).
I first set the background (in MainWindow) as bound to a property the represents the current page (the value is then being translated into a color hex code with the help of a converter).
All in all, this results in a case where the background changes when a page is changed, but not when the property inside MainPage changes. I can clearly understand why, but I have no idea how to solve it.
The possible solutions I came up with so far:
Somehow causing the binding in MainWindow to update/refresh when the property is changed in MainPage.
Changing the background manually from inside each of the pages. (Although doesn't it negate the idea of mvvm?)
Move the background into each of the pages and set it from there, while making the global buttons on top of the page (which could be a bad thing in case controls end up overlapping).
If so, what would be the best solution to this problem?
If you haven't already, I'd suggest you install some package via NuGet to make MVVM style development more enjoyable. I personally prefer MVVMLight which is... well, light, but it also packs lot's of helpful features.
To communicate between ViewModels, you have (at least) two possible approaches.
1) ViewModelLocator (not recommended)
ViewModelLocator is central place holding references to all of your viewmodels. You could add a property that is then used by all of the viewmodels to get/set the background.
....
x:Name="Main"
DataContext="{Binding Source={StaticResource Locator}, Path=MainVM}">
....
<Grid Background="{Binding Background, Converter={StaticResource StringBrushConverter}}">
...
2) Messenger (recommended)
When ever property changes in your viewmodel(s) or method is executed, you could send a message that your MainViewModel is registered to listen to. Sending a message would be as easy as...
Messenger.Default.Send(new UpdateBackgroundMessage(new SolidColorBrush(Colors.Blue)));
And you'd register for this message in your MainViewModel's constructor:
Messenger.Default.Register<UpdateBackgroundMessage>(this, message =>
{
Background = message.Brush;
});
Actual message class would be:
public class UpdateBackgroundMessage : MessageBase
{
public UpdateBackgroundMessage(Brush brush)
{
Brush = brush;
}
public Brush Brush { get; set; }
}
I know I'm simplifying things here but I hope you got the idea. Both approaches are valid even if you decide not to use MVVMLight.
Edit:
Here's Git repo with example https://github.com/mikkoviitala/cross-viewmodel-communication
I think you should use Application Properties for storing background. There are various benefit of this :
1) Globally available
2) Easy to remember or store user preference
3) Automatically maintain separate profile for each user as it store values in AppData folder of user.
you can use Messenger to notify that background property has changed so that main window or shell could pull out new background value and update it.
Yesterday I was refactoring some code in my windows phone project to try and use mvvm. I added binding to the toggleswitched on the page etc. the previous code also had evenhandlers for each toggleswitches checked and unchecked events. anyway I managed to clean it up. But my problem occured when I was trying to get code in my viewmodel to execute when i navigated away from this page. Initially I tried this
protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
{
viewmodel.SaveSettings();
}
after a bit of time debugging. I found this method wasnt being called. This was due to the fact that I was calling it in the code behind of a UserControl. Ive also tried to call the OnLostfocus() method when navigating away from the User control. but this doesnt work either. for the most part the project swaps in and out usercontrol elements in the main xaml.cs. mainly iam not really sure how to go about getting this method to be called when the usercontrol exits without destroying the mvvm structure i have i place now. any help would be greatly appreciated.
Solution:
oKay i figured this out. In my main.xaml is had a user contorls beign swapped in and out depending on menu item press by the user. the usercontorl in the main xaml looked like this
<UserControl x:Name="ActiveUserControl" Height="Auto" Width="480" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="1" Margin="0"/>
and it was swapped in and out using this command in the xaml.cs
ActiveUserControl.Content = _userControls["controlname"];
_usercontrols was just a dictionary of usercontrols. so in the onnavigatedfrom method in the main.xaml i changed the content of the ActiveuserControl to some other usercontrol. so if the home key was pressed on this usercontrol it would firethe unloaded event which fired then in the usercontol code behind this way it saved my settings.