0
votes

I have a MVVM WPF application from which I show a splash screen while some long task is done.

This splash screen is a typical WPF window and is very simple, it only has a label to show custom text such as "Loading..." and a spinner.

Its code-behind only has the constructor in which it is only performed the InitializeComponent and and event Window_Loaded.

From my main MVVM WPF application, when I perform a long task I instantiate this window and show the splash screen.

So now, I want to customize the text shown in the label in the splash screen. So what is the best approach?

What I have done is to pass as a parameter a string (custom message) to the constructor when I instantiate the window (Splash Screen).

Window mySplash = new SplashScreen("Loading or whatever I want");

As this splash screen is very simple, only a splash, I think it has no sense to apply MVVM here, so in the code-behind I create a private property which I set with the string passed as parameter to the constructor. Then, I bind the label in view with this private property and finally I implement INotifyPropertyChanged in the code-behind (view). There is no model, model view here.

Is that the correct way to do it? or is there any other way?

I know there is other solutions, like making public the label in the view by adding this:

x:FieldModifier="public"

and then access it once I instantiate the splash screen but I do not like this solution, I do not want to expose label outside.

ATTEMPT #1:

From my view model in main MVVM WPF application I perform below:

Window splashScreen = new SplashScreen("Loading ..."); 

Splash screen window:

<Window x:Class="My.Apps.WPF.SplashScreen"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid>
    <!-- Grid row and column definitions here -->
         <Label Grid.Row="0" Content="{Binding Path=Message}"/>  
    </Grid>
</Window>

Splash screen code-behind:

public partial class SplashScreen: Window
{
    public string Message
    {
        get
        {
            return (string)GetValue(MessageProperty);
        }
        set { SetValue(MessageProperty, value); }
    }
    public static readonly DependencyProperty
        MessageProperty =
        DependencyProperty.Register("Message",
        typeof(string), typeof(System.Window.Controls.Label),
        new UIPropertyMetadata("Working, wait ..."));

    public SplashScreen(string message)
    {
        InitializeComponent();

        if (!String.IsNullOrEmpty(message))
            this.Message = message;
    }

}

I have set a default value for Label.It will be used if it is not passed as a parameter to the constructor.

It is not working, in the xaml preview is not showing the default message in the label in the Visual Studio IDE environment. Also for some reason, when I pass as a parameter the custom message from the view model, it is not shown in the label. What am I doing wrong?

1
If you want to stay with MVVM, you could just add a DependencyProperty to your Window and bind the Label to it. - Manfred Radlwimmer
There is no need for MVVM or private properties here, just set the label text directly to passed string right in constructor. Though of course you should ensure that you are not instantiating that window from your viewmodel in main application, because it will break the whole concept. - Evk
@Evk Yes, I will instantiate the splash screen from my view model, and pass the custom string when I instantiate it. So better using a dependencyProperty then? as ManfredRadlwimmer has told. - Ralph
@user1624552 Not really, an attached Property would work too of course, but seems like unnecessary overhead. - Manfred Radlwimmer
You can pass some interface (IProgressDialog) to your view model, which will have Show(string text) and Hide methods, for example. One of the main goals of using MVVM is to decouple view from model. For example, you might want to use your view model as is with another UI (in Android application for example). Creating window (which is WPF control) from view model prevents doing that. - Evk

1 Answers

2
votes

You did not set DataContext for your grid:

<Window x:Class="My.Apps.WPF.SplashScreen"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Name="Splash"
>

    <Grid DataContext="{Binding ElementName=Splash}">
    <!-- Grid row and column definitions here -->
         <Label Grid.Row="0" Content="{Binding Path=Message}"/>  
    </Grid>
</Window>