简体   繁体   中英

Updating XAML component Visibility in real time - UWP

I have a periodic thread running in the background of my UWP application and I want to tie certain components' visibility to its execution. I am using caliburn and binding the component like this:

<TextBox Name="sample" Visibility="{Binding JobStatus}" />

C#:

public string JobStatus
{
    get
    {
        if(SponsorReferralUploadService.IsRunning())
            return "Collapsed";
        else
            return "Visible";
    }
}

This boolean value is coming from the service layer of the application so it is not possible for me to rewrite/redesign all that code and implement INotifyPropertyChanged interface.

When I open this page, the Visibility of the TextBox is set whether the boolean is true or false, how can I program this in a way that as soon as the value of the boolean is updated, the Visibility property is changed?

Have you tried INotifyPropertyChanged (namespace System.ComponentModel) event ?

event PropertyChangedEventHandler PropertyChanged;

To clarify, data bindings in WPF are not continuously re-evaluated. Once the UI gets a value for your JobStatus property, it's not going to ask again. Unless, that is, you tell it to.

The more common way to do this is to implement INotifyPropertyChanged on your ViewModel and then fire the PropertyChanged event. But you can also force the binding to update programmatically by calling the UpdateTarget method of the binding expression:

sample.GetBindingExpression(TextBlock.VisibilityProperty).UpdateTarget();

Without some sort of event telling you when to call this method, you'll be forced to call it repeatedly with a timer:

var timer = new System.Windows.Threading.DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1.0);
timer.Tick += timer_Tick;
timer.Start();
...
void timer_Tick(object sender, EventArgs e)
{
    sample.GetBindingExpression(TextBlock.VisibilityProperty).UpdateTarget();
}

But if you're using a timer anyway then you should really consider whether you ought to just put the timer in your ViewModel and use it to fire the PropertyChanged event. In my opinion, this sort of detail (ie an appropriate frequency for polling the service) ought to be in the ViewModel rather than the View.

public Visibility JobStatus
{
   get
   {
       if(SponsorReferralUploadService.IsRunning())
           return Visibililty.Collapsed;
       else
           return Visibililty.Visible;    
   }
}

if you are indeed using Caliburn.Micro then INPC is already incorporated into the framework using NotifyOfPropertyChanged(() => JobStatus); would need to be called when ever your SponsorReferralUploadService detects a change.

The tricky part here is how does it get this message if the SponsorReferralUploadService is a periodic service, then you would also need something along the lines of EventAggregator (maybe) to get it publish the change and have the IHandle to actually make the property update based on the published message, ie the actual call to NotifyOfPropertyChanged(() => JobStatus) . Think of EventAggregator as a cross viewmodel message pump, fire and forget, with that in mind, there is no guarantee of message delivery, usually related to viewmodel lifecycle.

This getter is actually way to big and only really needs 1 line of code and a Converter that is built into the BooleanToVisibilityConverter converter.

public bool JobStatus
{  
   get{
        return SponsorReferralUploadService.IsRunning();
   }
}

then as indicated Textbox would turn into this <TextBox Name="Sample" Visibility="{Binding JobStatus, Convert={StaticResource BoolVis}}" />

<Page.Resources> <cal:BooleanToVisibilityConverter x:Key="BoolVis" /> </Page.Resources>

Of course the blurb about getting the update still stands about who calls or checks for the property change.

For small application use mvermef said property code or otherwise use this.
For big applications use this boolean converter this will help u for more properties.

<TextBox Name="sample" Visibility="{Binding JobStatus,Converter={staticResource BooleanToVisibilityConverter}" />

public class BooleanToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (bool)value ? Visibility.Visible : Visibility.Collapsed;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM