Mohit S
Mohit S

Reputation: 14034

WPF Update UI while loading

I want to update the UI while loading some long work. What I want is when the data is loading I want to show an UserControl which is nothing but a wait message. I have tried BackgroundWorker, Dispatcher.BeginInvoke and ThreadPool.QueueUserWorkItem but I dont know why it is not doing as per the expectation. Please help

Dispatcher.BeginInvoke(new Action(() => img.Visibility = Visibility.Visible));
//Load some long wok here           
Dispatcher.BeginInvoke(new Action(() => img.Visibility = Visibility.Collapsed), DispatcherPriority.Background);

What I am looking for is to show an Image while loading and when load finish it must be collapsed.

Edit:

<Grid Grid.Column="2"
      Name="DetailsPane">
    <Grid.Background>
        <ImageBrush ImageSource="img/back.jpg"
                    Stretch="UniformToFill" />
    </Grid.Background>
    <Image Name="img"
           Margin="5"
           Stretch="None"
           Visibility="Collapsed" 
           Source="img/Loading.png" />
</Grid>

I have a Image to show while a loading is going on the Listbox SelectionChanged. So inside the SelectionChanged Event I'll be loading a detailed info in the Grid Called DetailsPane of a particular thing Cliked on the ListBox. While the loading of the info takes place how should I be showing this image on the DetailsPane?


Reached till here

Created a Dependency Property called State of type bool, then

.CS

private void LstAllFeatures_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    State = false;
    // Loading Heavy Work 
     State = true;
}

XAML

<Image Name="img"
       Margin="5"
       Stretch="None">
    <Image.Style>
        <Style TargetType="Image">
            <Setter Property="Visibility"
                    Value="Collapsed" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding State}"
                             Value="False">
                    <Setter Property="Visibility"
                            Value="Visible" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Image.Style>
</Image>

In DeatilsPane.Children -> _visualChildren -> InternalArray[0] is a Image. When open that in the WPF Visualizer Shows the Image Visibility = Visible but it doesn't show. Any Light on it please.

Upvotes: 0

Views: 1752

Answers (2)

Hamidreza A
Hamidreza A

Reputation: 46

first userControl must implement INotifyPropertyChanged like:

public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string      propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

then State must definition like:

public bool _state;
public bool State
    {
        get { return _state; }
        set
        {
            if (value != _state)
            {
                _state= value;
                RaisePropertyChanged();
            }
        }
    }

then in code where you want call LongWork()

State = true;
await Task.Run(()=>LongWork());
State = fasle;

then in xaml you write like:

<Image Margin="5"
   Stretch="None">
<Image.Style>
    <Style TargetType="Image">
        <Setter Property="Visibility"
                Value="Collapsed" />
        <Style.Triggers>
            <DataTrigger Binding="{Binding State,RelativeSource=   {RelativeSource AncestorType={x:Type test:UserControlName}},Mode=TwoWay}"
                         Value="False">
                <Setter Property="Visibility"
                        Value="Visible" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
   </Image.Style>
</Image>

Upvotes: 2

Sheridan
Sheridan

Reputation: 69959

Add a bool property:

public bool IsLoading
{
    get { return isLoading; }
    set { isLoading = value; NotifyPropertyChanged("IsLoading"); }
}

Data bind it to the Image.Visibility property:

<Image Margin="5" Stretch="None" Source="img/Loading.png"> 
    <Image .Style>
        <Style>
            <Setter Property="Control.Visibility" Value="Collapsed" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsLoading}" Value="True">
                    <Setter Property="Control.Visibility" Value="Visible" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Image.Style>
</Image>

Set it to true when you start your long running task on a background thread:

IsLoading = true;

Set it to false when your long running process is complete:

IsLoading = false;

Note that this will only work if you run your long running process on a background thread, otherwise, the UI thread will be busy and not update.

Upvotes: 0

Related Questions