-1

I have a WPF application in which I have overridden the OnClosing event so I do the following code:

protected override void OnClosing(CancelEventArgs e)
{
    this.Visibility = Visibility.Collapsed;
    e.Cancel = true;
}

so I can close and show the window again whenever I want. Also, the corresponding ViewModel is created once and when the window shows up again the binding works perfectly but the problem is when the window is closed and I update the ViewModel of the window and then I show the window again the bindings work perfectly but has a little delay which means I see the window first loads and then fields will be updated based on the updated value of the ViewModel when the window was closed. I'm looking for a solution to eliminate this delay so the window opens right away with the updated value

Inevitable
  • 37
  • 1
  • 5
  • Did you try using this.Hide() rather than visibility collapsed? – Andy Jan 04 '23 at 19:59
  • @Andy No, I think it solves the issue. I want to find the solution with this configuration until I have no choice :) – Inevitable Jan 04 '23 at 21:10
  • Perhaps it is not caused by binding but is common when updating UI while it is invisible. See [WPF update UI in while window is hidden](https://social.msdn.microsoft.com/Forums/en-US/e974c849-90ea-4741-9a27-0ae4857bc3c2/wpf-update-ui-in-while-window-is-hidden). It suggests a dirty but practical solution. – emoacht Jan 05 '23 at 05:13
  • It is not worth to keep the Window instance. Just create an new instance when required. This way you deal with the user's system resource more responsible. You can reuse the DataContext instance or persist the data and create a new DataContext too. Depends on your exact scenario. – BionicCode Jan 05 '23 at 09:13

1 Answers1

0

I think this problem results from the window's visibility change and even with Visibility.Hidden the problem still exists. so I'd recommend creating a new instance of the window every time you want to show it. you can do it by directly from your view project or if you have injected the window as a dependency to your ViewModel you can use the Activator.CreateInstance() method so you can handle it through your ViewModel project in the MVVM pattern.

EDIT: By dependency injection I mean something like the following pattern:

public interface IWindow
{
    void Show();
    void Close();
    bool? ShowDialog();

}

Now in View make a class like this:

public class BaseWindow : Window, IWinodw
{
     // Do everything you want
}

and make the actual window you are designing inherit from BaseWindow instead of a window. Also in your ViewModel class, you can have a property like this:

public IWindow MyWindow {get; set;}

and when you are initializing your app to start, inject the actual UI window to the ViewModel MyWindow by dependency injection. now in your ViewModel, you have full access to your view component (here window) to open and close it.

Daveed
  • 131
  • 1
  • 9
  • *"if you have injected the window as a dependency to your ViewMode" - What are you doing? *"you can use the Activator.CreateInstance()"* - The correct pattern would be to inject a factory. But you would and should never inject a Window to your View Model class. View Model classes don't participate in UI related logic n or do they handle controls or events published by controls. – BionicCode Jan 05 '23 at 09:09
  • The initial suggestion to create a new instance of the Window (from the View) is correct. But the rest is really bad code smell. – BionicCode Jan 05 '23 at 09:17
  • I know what dependency injection is. Because you inject the dependency as interface does not mean that your view model class is no longer implementing view logic. This is just dependency inversion. You r view model still implements logic that belongs to the view. In other words, the view model should never care about showing or displaying something or how data is presented (or if data is presented at all). Otherwise MVVM would be just to create an interface of Control and then move all the view code to the view model. Maybe this makes the wrong easier to understand. – BionicCode Jan 05 '23 at 12:03
  • This answer shouldn't be accepted. It breaks MVVM and spreads a very bad code smell. Hopefully not too many people will come accross your answer. It's plain wrong in terms of MVVM. MVVM and dependency inversion are two different things. Dependency inversion does not solve the problem that MVVM solves. This answer really hurts. – BionicCode Jan 05 '23 at 12:05
  • @BionicCode I don't know what are you talking about. if this is not true anser show me the solution to how you open or close your view through ViewModel without using code-behind. every example of opening and closing dialog on the internet uses a similar pattern by defining services as interfaces and then using dependency injection to provide value for that service – Daveed Jan 05 '23 at 12:27
  • @BionicCode How do you navigate between views from ViewModel? how do you for example open a close-dialog and show it to users with services and avoid dirty code-behind style? – Daveed Jan 05 '23 at 12:30
  • @BionicCode so if you are right this link is wrong https://www.youtube.com/watch?v=U7Qclpe2joo – Daveed Jan 05 '23 at 12:32
  • @BionicCode I read your guy's discussion about accessing view objects in ViewModel and had a quick search here and found this question and its https://stackoverflow.com/questions/47266184/getting-window-from-view-model answer that is similar to Daveed's one – Inevitable Jan 05 '23 at 12:51
  • Yes there are tons of examples on the internet that are wrong. That's the nature of the internet. Everybody can post something. It's not programming alone. We can generally say that there is a lot of false information on the internet. – BionicCode Jan 05 '23 at 12:53
  • *"How do you navigate between views from ViewModel?"* -You display views by exposing a data model which you have created a DataTemplate for. Same you do wit ha ListBox. You don't pass an IListBox to the view model. You create DataTemplates that the view uses to generate controls to present the data: [C# WPF Navigation Between Pages (Views)](https://stackoverflow.com/a/61323201/3141792). – BionicCode Jan 05 '23 at 12:53
  • *"avoid dirty code-behind style"* - That's the key point many tutorials get wrong. MVVM is not about code-behind. It's about application level separation of responsibilities. Code-behind is a language/compiler feature (`partial class`). Design patterns are not language specific - that's a major requirement in order to be called "Design Pattern". – BionicCode Jan 05 '23 at 12:53
  • In fact you can't develop controls without code-behind (C#). XAML is not powerful enough to implement complex logic. Sometimes you also want to extend an existing control to change it's behavior. For this you have to override virtual members. Showing dialogs based on Window from code-behind is he only way to go if you want to implement MVVM correctly. This Window will also have a DataContext. – BionicCode Jan 05 '23 at 12:54
  • In MVVM data and data presentation are strictly separated. – BionicCode Jan 05 '23 at 12:54
  • @Inevitable Now with Daveed's answer you will find another wrong example. In MVVM you simply don't do this. If want to show something from the View Model, then your design is wrong. Your classes have wrong responsibilities too. You must think different. In MVVM it is essential to understand that the View Model is completely unaware that there is a user and a UI. If you are unaware that there exists a user, then why would want to interact with one? – BionicCode Jan 05 '23 at 12:57
  • Take the WPF data validation concept as a good example. You validate properties. If you found an error you store an error message along with the property name. Then you raise an event that singnals any listener that the view model class has an error (invalid data). It doesn't know about a view at this point and it never does. The view listens to this event as it knows its view models. The view then decides to give the user a feedback e.g., by displaying a red border. - You can learn from this flow how responsibilities are separated. The view model does not actively participate in view logic. – BionicCode Jan 05 '23 at 13:02
  • The view model does not directly interact with the user, but the view does. It forces the user to correct his input. The corrected input is then send back to the view model e.g. via data binding. The validation procedure begins from the start. The communication between the view model and view (user) is broken up. The view is in charge of handling the user feedback. The view model only operates on data level. It doesn't care who corrects the input. It just rejects data and raises an event. – BionicCode Jan 05 '23 at 13:08
  • @BionicCode I would like to appreciate your great explanation about different aspects of the concept. now I agree with you and I also believe that myself is biased about the fact that having code behind is a very bad practice. I think we should have a balance between MVVM and code-behind if we manage to do all the things from ViewModel we may end up breaking MVVM pattern unintentionally in the hope we don't do it :). so now we finalize our discussion that having code-behind sometimes is necessary. If there is any other point let us to know :) – Daveed Jan 05 '23 at 13:11
  • Following this pattern you could also think about to raise an event that the view can handle by displaying a dialog. But be very careful to not let UI bleed into your view model. The event must be very unspecific, like the Error event. Generally you must validate every user input using the proper technique (implement INotifyDataErrorInfo). This also eliminates the need to show a dialog to ask the user for input. – BionicCode Jan 05 '23 at 13:12
  • It's good to do as much as you can in XAML. XAML is a markup language that is great to visualize the UI structure, which is a tree. The paradigm to not use code-behind has a different origin. It's from those days when WInForms developers switched to WPF. In WinForms you don't have markup. Everything is done in C#, which was quite a mess. But if you have worked with WinForms for years or decades it is difficult to change the learned coding style and you naturally tend to do too much in C#, things that are easier and more readable in XAML. XAML was not meant to replace C#. – BionicCode Jan 05 '23 at 13:17
  • Fwiw I also think the approach posted is far from ideal. I was amused to see who wrote that linked answer. Which was also poor. I used to do winforms myself. Saw Wpf and mvvm and realised it was a far better way to work. A window is a content control you can easily template out that content into a usercontrol associated with a viewmodel type and have just one single window type hosts anything. – Andy Jan 05 '23 at 19:45