Cudack
Cudack

Reputation: 15

Problems with binding values

I'm having a problem with binding values to controls. I checked in other windows I have and I think I'm doing it the same way. I want to show something like loading window from App before main window will open. The problem is nothing is changing (text/content/value of controls).

InitizalizationWindow:

public InitializationWindow()
{
    ...
    InitializationWindowClass.Progress = new InitializationWindowClass();
    this.mainSP.DataContext = InitializationWindowClass.Progress;
}

and part of xaml:

<StackPanel Name="mainSP" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="0, 0, 0, 10">
    <TextBlock x:Name="tblProgress" FontSize="14" Text="{Binding ProgressText}" TextAlignment="Center" TextWrapping="Wrap" />
    <Grid>
            <telerik:RadProgressBar x:Name="progress" Value="{Binding ProgressValue}" telerik:StyleManager.Theme="Summer" Height="25" IsIndeterminate="False" />
            <Label x:Name="lblPercent" FontWeight="Bold" Content="{Binding ProgressValueString}" HorizontalAlignment="Center" VerticalContentAlignment="Center" />
    </Grid>
</StackPanel>

InitializationWindowClass:

public class InitializationWindowClass : INotifyPropertyChanged
{
    public static InitializationWindowClass Progress { get; set; }
    private string progressText = String.Empty, progressValueString = String.Empty;
    private int progressValue = 0;
    public event PropertyChangedEventHandler PropertyChanged;

    public string ProgressText
    {
        get
        {
            return progressText;
        }
        set
        {
            progressText = value;
            NotifyPropertyChanged("ProgressText");
        }
    }

    public string ProgressValueString
    {
        get
        {
            return progressValueString;
        }
        set
        {
            progressValueString = value;
            NotifyPropertyChanged("ProgressValueString");
        }
    }

    public int ProgressValue
    {
        get
        {
            return progressValue;
        }
        set
        {
            progressValue = value;
            ProgressValueString = String.Format("{0}%", progressValue);
            NotifyPropertyChanged("ProgressValue");
            NotifyPropertyChanged("ProgressValueString");
        }
    }

    private void NotifyPropertyChanged(String propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

and part of App.xaml.cs:

protected override void OnStartup(StartupEventArgs e)
{
    InitializationWindow iw = new InitializationWindow(); 
    iw.Show();
    InitializationWindowClass.Progress.ProgressValue = Convert.ToInt32(((decimal)count / (decimal)sum) * 100);
    InitializationWindowClass.Progress.ProgressText = "Some text";
    ...
    ...
    InitializationWindowClass.Progress.ProgressValue = Convert.ToInt32(((decimal)count / (decimal)sum) * 100);
    InitializationWindowClass.Progress.ProgressText = "New text";
    ...
    ...
}

I checked and when I'm changing i.e. ProgressValue from App.xaml.cs, the value is changing - going to

get
{
    return progressValue;
}

So the question is - what I'm doing wrong?

Upvotes: 0

Views: 119

Answers (2)

Arie
Arie

Reputation: 5373

What you are doing won't work. You are displaying your splash screen and performing load operations on the same thread. This way, while your loading operations run, the main UI thread is busy and is not updating, even if the data in the background are changing properly. That's why you are probably seing "wait" cursor, your splash window is unresponsive, and your main window may not even appear at all.

  • SplashScreen should be displayied on different thread
  • You have to have a way of communicating with that thread, because:
  • you can't directly update UI from one thread using another thread

Here you have a nice example of working SplashScreen in wpf

Upvotes: 0

Steven Rands
Steven Rands

Reputation: 5421

This is a threading issue. Binding changes are posted to the Dispatcher, and then the UI thread pulls those events out of the Dispatcher queue and processes them.

Here you are making changes to the bindings in the OnStartup event, which itself is being handled by the UI thread. This means that those binding changes won't be handled until the OnStartup event is exited. What you probably end-up seeing in your user interface is just the values of those progress properties when they were last changed.

What you need to do is move the progress reporting to another thread. In other words, shift the work currently done in the OnStartup event to a different thread, using async/await or some other threading mechanism.


Original, incorrect answer follows:

ProgressText, ProgressValueString and ProgressValue are all properties on InitializationWindowClass, not InitializationWindow. It looks like you need to either set the DataContext on the StackPanel to point at the Progress property of the InitializationWindow, or include the Progress property as part of the binding path for the individual elements.

That is, either this:

<StackPanel ... DataContext="{Binding Progress}">
    ... rest the same ...
</StackPanel>

or this:

<StackPanel ...>
    <TextBlock ... Text="{Binding Progress.ProgressText}" ... />
    <Grid>
        <telerik:RadProgressBar ... Value="{Binding Progress.ProgressValue}" ... />
        <Label ... Content="{Binding Progress.ProgressValueString}" ... />
    </Grid>
</StackPanel>

Upvotes: 1

Related Questions