Search code examples
c#wpfdevexpressviewmodel

ViewModel issue


I need pop up a window which takes time. The button is in Pressed state until the new window is opened. Hence I want to add a wait indicator over the UI window after I click the button and before the the window opens. The code of ViewModel is correct because I referred to a sample code. But why there is no response after I click the button.

The project file URL

https://supportcenter.devexpress.com/attachment/file/5268961b-ce35-4e40-b7c1-e33bffab902b

MainWindow:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DevExpress.Xpf.Core;

namespace WaitIndicatorDemo
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : DXWindow
    {

        public MainWindow()
        {
            InitializeComponent();
            vm = new MainVM();
            DataContext = vm;
        }

        MainVM vm;

        private void buttonShow_Click(object sender, RoutedEventArgs e)
        {
            vm.IsBusy = !vm.IsBusy;
        }
    }
}

ViewMode:

    using DevExpress.Mvvm;

namespace WaitIndicatorDemo
{
    public class MainVM
    {
        private readonly ISplashScreenService _waitIndicatorService;

        public virtual bool IsBusy { get; set; }

        public MainVM()
        {
            _waitIndicatorService = 
                ServiceContainer.Default.GetService<ISplashScreenService>("WaitIndicatorService");
        }

        protected void OnIsBusyChanged()
        {
            if (IsBusy)
                _waitIndicatorService.ShowSplashScreen();
            else
                _waitIndicatorService.HideSplashScreen();
        }
    }
}

Below is the XAML, the comment ones are the original sample code. The checkbox bind to IsBusy. The indicator pop up when the checkbox is checked. I now want to pop up after press the button.

    <dx:DXWindow x:Class="WaitIndicatorDemo.MainWindow"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
             xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
             xmlns:waitIndicatorDemo="clr-namespace:WaitIndicatorDemo"
             xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
             WindowStartupLocation="CenterScreen" SnapsToDevicePixels="True"
               Title="MainWindow" Height="350" Width="525">
             <!--DataContext="{dxmvvm:ViewModelSource Type=waitIndicatorDemo:MainVM}"-->
             <!--Title="MainWindow" Height="350" Width="525">-->

    <Grid Margin="10">
        <!--<dxe:CheckEdit Content="Is Busy" IsChecked="{Binding IsBusy}" 
                       VerticalAlignment="Top" HorizontalAlignment="Left" />

        <Button Content="Button1" IsEnabled ="{Binding IsBusy, Converter={dxmvvm:BooleanNegationConverter}}"
                VerticalAlignment="Top" HorizontalAlignment="Center" Click="Button_Click"/>

        <Button Content="Button2" IsEnabled="{Binding IsBusy, Converter={dxmvvm:BooleanNegationConverter}}"
                VerticalAlignment="Top" HorizontalAlignment="Right"/>-->
        <Button x:Name="buttonShow" Content="Show"  HorizontalAlignment="Left" Height="35" Margin="50,70,0,0" VerticalAlignment="Top" Width="75" Click="buttonShow_Click" />

    </Grid>
</dx:DXWindow>

Solution

  • You have a few mistakes in your code sample :
    1- The method OnIsBusyChanged in your ViewModel is never called.
    2- Your XAML doesn't declare any ISplashScreenService object in the Window behaviors, like a DXSplashScreenService for instance.

    Here's how you can fix both of those issues.

    First, fix the ViewModel.

    public class MainVM
    {
        private readonly ISplashScreenService _waitIndicatorService;
    
        private bool _isBusy;
        public virtual bool IsBusy 
        {
            get
            {
                return _isBusy;
            }
    
            set
            {
                _isBusy = value;
                OnIsBusyChanged();
            }
        }
    
        public MainVM()
        {
            _waitIndicatorService = 
                ServiceContainer.Default.GetService<ISplashScreenService>("WaitIndicatorService");
        }
    
        protected void OnIsBusyChanged()
        {
            _waitIndicatorService.SetSplashScreenState("Doing some work...");
    
            if (IsBusy)
                _waitIndicatorService.ShowSplashScreen();
            else
                _waitIndicatorService.HideSplashScreen();
        }
    }
    

    Then, your XAML.

    <dx:DXWindow x:Class="WaitIndicatorDemo.MainWindow"
        <!-- ... -->
        Title="MainWindow" Height="350" Width="525">
    
        <dxmvvm:Interaction.Behaviors>
            <dx:DXSplashScreenService x:Name="WaitIndicatorService">
                <dx:DXSplashScreenService.ViewTemplate>
                    <DataTemplate>
                        <Grid>
                            <Border Background="LightGray" CornerRadius="5">
                                <Border BorderBrush="#FF0072C6" BorderThickness="1" Margin="15" CornerRadius="5">
                                    <Grid>
                                        <ProgressBar BorderThickness="0" Value="{Binding Progress}" Maximum="{Binding MaxProgress}" IsIndeterminate="{Binding IsIndeterminate}" Height="12" />
                                        <TextBlock Text="{Binding State, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                                    </Grid>
                                </Border>
                            </Border>
                        </Grid>
                    </DataTemplate>
                </dx:DXSplashScreenService.ViewTemplate>
            </dx:DXSplashScreenService>
        </dxmvvm:Interaction.Behaviors>
    
        <Grid Margin="10">
            <!-- ... -->
        </Grid>
    </dx:DXWindow>
    

    This code was mainly taken from the How to: Use DxSplashScreenService sample.