Changing a Label when a Bool variable turns True

2019-07-05 15:42发布

问题:

i'm not really sure how to explain this... i'm going to put the code in psuedo code for easy reading

pretty much I want a label to change it's text when a bool variable of a class changes... i'm not sure what I need to use since i'm using WPF and the class can't just change the label i don't think?

do i need some sort of event? or a WPF event? thanks for any help

public MainWindow()
{
   SomeClass temp = new SomeClass();

   void ButtonClick(sender, EventArgs e)
   {  
      if (temp.Authenticate)
        label.Content = "AUTHENTICATED";
   }
}

public SomeClass
{
  bool _authenticated;

  public bool Authenticate()
  {
    //send UDP msg
    //wait for UDP msg for authentication
    //return true or false accordingly
  }
}

回答1:

Another WPF approach other than BradledDotNet answer is to use triggers. This will be purely XAML based without converter code.

XAML:

<Label>
  <Label.Style>
    <Style TargetType="Label">
      <Style.Triggers>
        <DataTrigger Binding="{Binding Path=IsAuthenticated}" Value="True">
          <Setter Property="Content" Value="Authenticated" />
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </Label.Style>
</Label>

Same rule applies as mentioned by BradledDotNet, ViewModel should be attached and "IsAuthenticated" property should raise the PropertyChanged event.

-- Add some boilerplate code as suggested by Gayot Fow --

View Code Behind:

For simplicity I will just set the DataContext of the view in code behind. For a better design you can use ViewModelLocator as explained here.

public partial class SampleWindow : Window
{
  SampleModel _model = new SampleModel();

  public SampleWindow() {
    InitializeComponent();
    DataContext = _model; // attach the model/viewmodel to DataContext for binding in XAML
  }
}

Example Model (it should really be ViewModel):

The main point here is the attached model/viewmodel has to implement INotifyPropertyChanged.

public class SampleModel : INotifyPropertyChanged
{
  bool _isAuthenticated = false;

  public bool IsAuthenticated {
    get { return _isAuthenticated; }
    set {
      if (_isAuthenticated != value) {
        _isAuthenticated = value;
        OnPropertyChanged("IsAuthenticated"); // raising this event is key to have binding working properly
      }
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  void OnPropertyChanged(string propName) {
    if (PropertyChanged != null) {
      PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }
  }
}


回答2:

Since we are using WPF, I would use a binding and converter to accomplish this:

<Page.Resources>
   <local:BoolToAuthenticationStringConverter x:Key="BoolToAuthenticationStringConverter"/>
</Page>

<Label Content="{Binding Path=IsAuthenticated, Converter={StaticResource BoolToAuthenticationStringConverter}"/>

Then a converter that looks like:

public class BoolToAuthenticationStringConverter : IValueConverter
{
   public object Convert (...)
   {
      if ((bool)value)
         return "Authenticated!";
      else
         return "Not Authenticated!";
   }

   public object ConvertBack (...)
   {
      //We don't care about this one for this converter
      throw new NotImplementedException();
   }
}

In our XAML, we declare the converter in the resources section, then use it as the "Converter" option of the binding for "Content". In the code, we cast value to a bool (IsAuthenticated is assumed to be a bool in your ViewModel), and return an appropriate string. Make sure your ViewModel implements INotifyPropertyChanged and that IsAuthenticated raises the PropertyChanged event for this to work!

Note: Since you won't be changing the Label via the UI, you don't need to worry about ConvertBack. You could set the mode to OneWay to make sure that it never gets called though.

Granted, this is very specific to this scenario. We could make a generic one:

<Label Content="{Binding Path=IsAuthenticated, Converter={StaticResource BoolDecisionToStringConverter}, ConverterParameter='Authenticated;Not Authenticated'}"/>

Then a converter that looks like:

public class BoolDecisionToStringConverter : IValueConverter
{
   public object Convert (...)
   {
      string[] args = String.Split((String)parameter, ';');
      if ((bool)value)
         return args[0];
      else
         return args[1];
   }

   public object ConvertBack (...)
   {
      //We don't care about this one for this converter
      throw new NotImplementedException();
   }
}


回答3:

Yes, you need an event.

Consider a sample like this:

public SomeClass {
    public event EventHandler<EventArgs> AuthenticateEvent;  
    boolean isAuthenticated;

    public bool Authenticate()
    {
        // Do things
        isAuthenticated = true;
        AuthenticateEvent(this, new EventArgs());
    }
}

public MainWindow()
{
   SomeClass temp = new SomeClass();

   public MainWindow(){
      temp.AuthenticateEvent+= OnAuthentication;
      temp.Authenticate();
   }

   private void OnAuthentication(object sender, EventArgs e){
       Dispatcher.Invoke(() => {
           label.Content = "AUTHENTICATED";
       }); 
   }
}

Now whenever temp fires the Authenticate event, it will change your label.