none
Bind Visibility of a control in MVVM?

    Question

  • Hi All,

    Am developing Windows 8 App,

    where in my app am using MVVM flow.

    On Click of Login Am Binding Login Button with relay command in ViewModel

    and also i want show Progress bar(i.e., ...Loading Please wait) to the user at the same time.

    how do i achieve the same in viewmodel.

    Any suggestion would be of great help

    Thanks



    Arjun

    Monday, May 05, 2014 9:38 AM

All replies

  • Hi Arjun,

    I believe you will need to create a Visibility property in the ViewModel and bind it to the ProgressBar's Visibility property in the View. You can try this through the Command binding inside DataTemplate   sample.

    Sagar

    Monday, May 05, 2014 1:09 PM
  • Hi Thanks For Your Reply,

    But It is not helping me out..


    Arjun

    Monday, May 12, 2014 9:37 AM
  • Hello,

    You can take a look at the System.Progress class which can help you report progress through a value to the View. For that, you can create a simple class which can return (say int) values which will help track progress. Example:

      public class MyProgress
        {
            public int Progress { get; set; }
        
        }

    Then, you need pass IProgress<MyProgress> to the function which you need to monitor for processing. Say in above sample, it is GetData – which would then look like this:

    public static ObservableCollection<Customer> GetData(IProgress<MyProgress> progress)

    And you can use the IProgress<T>.Report method to return the result of processing:

    int totalCount = 10; int tempCount = 0; for (int i = 1; i <= 10; i++) { //add data to collection //do processing here...

    if (progress != null) { progress.Report(new MyProgress() { Progress = (tempCount * 100 / totalCount) }); } tempCount++; }

    Then, in View-Model, you can define the variable that can track the progress as well as the function that can receive the progress from above GetData function :

    var progressReporter = new Progress<MyProgress>(ReportProgress);
    Customers = InitializeSampleData.GetData(progressReporter);
    

    The ReportProgress function can be defined in ViewModel  as :

    void ReportProgress(MyProgress prg)
    {
    //this method will be called for every call of progress.report() in GetData() method above
    
    ProgressValue = prg.Progress;
            
    }

    And the ProgressValue variable can be defined in ViewModel as :

    int  _ProgressValue;
    public  int ProgressValue
    {
    get { return _ProgressValue; }
    set
    {
    _ProgressValue = value;
    OnPropertyChanged("ProgressValue");
    }
    }


    Finally, in the XAML, you can bind the variable to ProgressBar as :

    <ProgressBar x:Name="ProgressIndicator" Height="30" IsEnabled="True" Value="{Binding ProgressValue}" Grid.Row="1" IsIndeterminate="False"></ProgressBar>


    Make sure you set the DataContext object on the Page/UserControl level to make it workdepending on the usage. You can modify the functionality for Visibility when the ProgressValue approaches 100% .

    Reference:

    http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis.aspx

    Sagar






    Monday, May 12, 2014 4:37 PM
  • Hi Sagar Thanks For your reply,

    Here is My Piece Of Code Which Am working on.

    <TextBox x:Name="ServerTextBox" Grid.Row="0" Grid.Column="1" Style="{StaticResource LoginFormTextBoxStyle}" PlaceholderText="{Binding EnterServer}" Margin="5,10,0,10" Text="{Binding URL,Mode=TwoWay}">
                        <interactivity:Interaction.Behaviors>
                            <behaviors:HighlightFormFieldOnErrors PropertyErrors="{Binding  Validation.Errors[Url]}" />
                        </interactivity:Interaction.Behaviors>
                    </TextBox>
                    <TextBox x:Name="UserTextBox" Grid.Column="1" Grid.Row="1" TextWrapping="Wrap" Text="{Binding UserName,Mode=TwoWay}" Style="{StaticResource LoginFormTextBoxStyle}" PlaceholderText="{Binding EnterUsername}" Margin="5,10,0,10">
                        <interactivity:Interaction.Behaviors>
                            <behaviors:HighlightFormFieldOnErrors PropertyErrors="{Binding  Validation.Errors[Input]}" />
                        </interactivity:Interaction.Behaviors>
                    </TextBox>
                    <PasswordBox x:Name="PasswordTextBox" Password="{Binding Password,Mode=TwoWay}" Grid.Column="1" Grid.Row="2" Tapped="PasswordTextBox_Tapped" Style="{StaticResource LoginPasswordTextBoxStyle}" PlaceholderText="{Binding EnterPassword}" IsPasswordRevealButtonEnabled="True" Margin="5,10,0,10">
                    </PasswordBox>
                    <Button x:Name="LoginButton" Content="{Binding Login}" Grid.Column="1" Grid.Row="4" Style="{StaticResource MojoButtonStyle}" Tapped="LoginButton_Tapped" Command="{Binding cmdLoginClick}" />


    public string CheckAuthentication(string UsernameParam, string PasswordParam, string Urlparam) { Result = (ObjSys.CheckUserName(UsernameParam, PasswordParam, Urlparam)); if (Result == "Initial Sync") { IsSyncing = true; IAsyncAction objCreateThread = Windows.System.Threading.ThreadPool.RunAsync( (source) => { ServiceSyncViewModel ObjServiceSync = new ServiceSyncViewModel(); ObjServiceSync.ServiceURL = Urlparam; ObjServiceSync.UserName = UsernameParam; ObjServiceSync.Password = PasswordParam; if (ObjServiceSync.StartSync() == true) {

    IsNavigate = true; } } ); } }

    When Result == "Initial Sync" This Happens in Want That Busy Indicator to show in My View. till that time i dont want busy indicator.



    Arjun

    Tuesday, May 13, 2014 5:35 AM
  • Is the above method “CheckAuthentication” in the ViewModel? If yes, then you might to make Result -  a property in the ViewModel.

    Then, for toggling the Visibility of the ProgressBar based on the value of Result, you’ll have to write a IValueConverter that maps “Initial Sync” to Visibility of the ProgressBar.

    Something like:

    public class CustomValueConverter : IValueConverter
        {
            object IValueConverter.Convert(object value, Type targetType, object  parameter, string language)
            {
    
                if (value.ToString() == "Initial Sync")
                {
                    return Windows.UI.Xaml.Visibility.Visible;
    
                }
                else
                {
                    return Windows.UI.Xaml.Visibility.Collapsed;
    
                }
            }
    
            object IValueConverter.ConvertBack(object value, Type targetType, object parameter, string language)
            {
                throw new NotImplementedException();
            }
    


    Create an instance of CustomValueConverter in Page.Resources section of the View :

    <common:CustomValueConverter x:Key="VisibilityConverter" />


    Bind it to the ProgressBar in the View as:

    <ProgressBar x:Name="ProgressIndicator" Visibility="{Binding Path=Result,Converter={StaticResource VisibilityConverter}}" Height="30" IsEnabled="True" Grid.Row="1" IsIndeterminate="True"></ProgressBar>

    Hope that helps.


    Sagar


    Tuesday, May 13, 2014 10:56 AM
  • This IS how My Screen looks After Making those changes. Do i Need to Change Any where else?? Am not getting any progress ring.

    Thanks


    Arjun

    Tuesday, May 13, 2014 12:34 PM
  • I think you need to check the placement of the ProgressBar and test if it's not set to Visibility.Collapsed - you can do this by putting a breakpoint in Convert method of the IValueConverter class. Also, while testing you can set the value of Visibility property to Visible and check where the ProgressBar has appeared on the screen/Page.

    Sagar

    Tuesday, May 13, 2014 2:57 PM
  •         private string _Result = string.Empty;
            public string Result
            {
                get { return _Result; }
                set
                {
                    if (_Result == value)
                        return;
                    _Result = value;
                    RaisePropertyChanged("Result");
    
                }
            }
    
        public  string CheckAuthentication(string UsernameParam, string PasswordParam, string Urlparam)
            {
    
    Result = (ObjSys.CheckUserName(UsernameParam, PasswordParam, Urlparam));
                            if (Result == "Initial Sync")
                            {
                                
                                IAsyncAction objCreateThread = Windows.System.Threading.ThreadPool.RunAsync(
                                    (source) =>
                                    {
                                        ServiceSyncViewModel ObjServiceSync = new ServiceSyncViewModel();
                                        ObjServiceSync.ServiceURL = Urlparam;
                                        ObjServiceSync.UserName = UsernameParam;
                                        ObjServiceSync.Password = PasswordParam;
                                        if (ObjServiceSync.StartSync() == true)
                                        {
                                            IsNavigate = true;
    
    //Start Sync Will Take Around 4 Mins to Sync Data To Client.
                                        }
                                    }
                                );
    }
    }

    Above Start Sync Will TAke Around 4 Mins to Download Data From Server.

    This Is How My Visibility Converter Looks

     public class CustomValueConverter : IValueConverter
        {
            object IValueConverter.Convert(object value, Type targetType, object parameter, string language)
            {
    
                if (value.ToString() == "Initial Sync")
                {
                    return Windows.UI.Xaml.Visibility.Visible;
    
                }
                else
                {
                    return Windows.UI.Xaml.Visibility.Collapsed;
    
                }
            }
    
            object IValueConverter.ConvertBack(object value, Type targetType, object parameter, string language)
            {
                throw new NotImplementedException();
            }
    
        }

    This Is My XAML

    <Page
        x:Name="pageRoot"
        x:Class="Sample.Login"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:Sample"
        xmlns:common="using:Sample.Common"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" Background="{x:Null}"
        xmlns:behaviors="using:Sample.Behaviors"
        xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
        xmlns:vm="using:Sample.ViewModels"
        xmlns:DP="using:Telerik.UI.Xaml.Controls.Input"
        xmlns:prism="using:Microsoft.Practices.Prism.StoreApps" >
        <Page.DataContext>
            <vm:LoginViewModel/>
        </Page.DataContext>
        
        
        <Page.Resources>
            <common:BooleanToVisibilityConverter x:Key="booleanToVisibilityConverter"/>
            <common:CustomValueConverter x:Key="VisibilityConverter" />
        </Page.Resources>
    
        
    
        <Grid x:Name="BackgroundGrid" Style="{StaticResource LoginBackgroundGridImageStyle}">
            <Grid.ChildrenTransitions>
                <TransitionCollection>
                    <EntranceThemeTransition/>
                </TransitionCollection>
            </Grid.ChildrenTransitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
    
            <!-- Back button and page title -->
            <Grid x:Name="LayoutGrid" Margin="50,100,50,50">
                <Grid.RowDefinitions>
                    <RowDefinition Height="1*"/>
                    <RowDefinition Height="3*"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="6*"/>
                    <ColumnDefinition Width="4*"/>
                    <ColumnDefinition Width="2*"/>
                </Grid.ColumnDefinitions>
                <Grid x:Name="LoginForm" Grid.Row="1" Grid.Column="1" Margin="0,25,0,0">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="3*"/>
                    </Grid.ColumnDefinitions>
    
                    <TextBlock x:Name="ServerTextboxLabel" Text="{Binding Server}" Style="{StaticResource LoginFormLabelStyle}"/>
                    <TextBlock x:Name="UserTextboxLabel" Grid.Row="1" Grid.Column="0" Text="{Binding User}" Style="{StaticResource LoginFormLabelStyle}"/>
                    <TextBlock x:Name="PasswordTextboxLabel" Grid.Row="2" Grid.Column="0" Text="{Binding PasswordL}" Style="{StaticResource LoginFormLabelStyle}"/>
                    <StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="3">
                        <CheckBox x:Name="SaveCredCheckbox" Style="{StaticResource MojoFormCheckboxStyle}" IsChecked="True" />
                        <TextBlock x:Name="SaveCredCheckboxLabel" Style="{StaticResource GrayBodyTextBlockStyle}" Margin="2,4,0,0" Text="{Binding SaveCredentials}"/>
                    </StackPanel>
                    <TextBox x:Name="ServerTextBox" Grid.Row="0" Grid.Column="1" Style="{StaticResource LoginFormTextBoxStyle}" PlaceholderText="{Binding EnterServer}" Margin="5,10,0,10" Text="{Binding URL,Mode=TwoWay}">
                        <interactivity:Interaction.Behaviors>
                            <behaviors:HighlightFormFieldOnErrors PropertyErrors="{Binding  Validation.Errors[Url]}" />
                        </interactivity:Interaction.Behaviors>
                    </TextBox>
                    <TextBox x:Name="UserTextBox" Grid.Column="1" Grid.Row="1" TextWrapping="Wrap" Text="{Binding UserName,Mode=TwoWay}" Style="{StaticResource LoginFormTextBoxStyle}" PlaceholderText="{Binding EnterUsername}" Margin="5,10,0,10">
                        <interactivity:Interaction.Behaviors>
                            <behaviors:HighlightFormFieldOnErrors PropertyErrors="{Binding  Validation.Errors[Input]}" />
                        </interactivity:Interaction.Behaviors>
                    </TextBox>
                    <PasswordBox x:Name="PasswordTextBox" Password="{Binding Password,Mode=TwoWay}" Grid.Column="1" Grid.Row="2" Tapped="PasswordTextBox_Tapped" Style="{StaticResource LoginPasswordTextBoxStyle}" PlaceholderText="{Binding EnterPassword}" IsPasswordRevealButtonEnabled="True" Margin="5,10,0,10">
                    </PasswordBox>
                    <Button x:Name="LoginButton" Content="{Binding Login}" Grid.Column="1" Grid.Row="4" Style="{StaticResource MojoButtonStyle}" Tapped="LoginButton_Tapped" Command="{Binding cmdLoginClick}" />
                </Grid>
                <Image Grid.Row="0" Grid.Column="1" Style="{StaticResource LoginLogoHeaderImageStyle}"/>
                <Image Grid.Column="2" Grid.Row="2" Style="{StaticResource LoginLogoBottomImageStyle}"/>
            </Grid>
    
    
            <ProgressBar x:Name="ProgressIndicator" Visibility="{Binding Path=Result,Converter={StaticResource VisibilityConverter}}" Height="30" IsEnabled="True" Grid.Row="1" IsIndeterminate="True"></ProgressBar>
           
        </Grid>
    </Page>


    My ViewModel Class looks Like this

        public class LoginViewModel : ViewModelBase, INotifyPropertyChanged
        {
    }


    Where Am Missing.. 

    After All The Corrections My Screen is Still Looking the same..


    i Am Navigating user to Some other page after downloading the data from server.,But if i dont navigate My progress bar is visible after tht"Checkuserauthentication method completes" 

    CheckAuthentication() is in My Login View Model.

    Am Calling this Methid through Relay Command.

    Arjun



    Wednesday, May 14, 2014 6:03 AM