Implementing a Boolean INotifyPropertyChanged : Not Updating

vzmon1 41 Reputation points
2022-02-21T19:25:20.757+00:00

176484-booleaninotifypropertychanged1.pdf

I'm new to WPF, as a learning project I'm attempting to create a Windows' app that (1) visually indicates whether or not I'm connected to the server, (2) and lists a list of Task Jobs on the server.
For (1) where I'm currently stuck, I have created:

  • An Observable class that implements the INotifyPropertyChanged interface
  • StatusControl (UserControl) to display an Ellipse; Red for not connected, Green if it is connected
  • StatusViewModel that will set the property ConnectedToServer to true if I can reach the server and the Task Job service
  • On the StatusControl.xaml.cs file I'm subscribing to the event StatusViewModel.PropertyChanged via += <method>; in the constructor

I'm unable to get the ellipse to change color even though I'm connected. It seems to by pass my subscription to the event. The majority of examples I have read are working with UI Elements, so I'm not sure if I'm going about this the wrong way. Any guidance / suggestions that can be provided is greatly appreciated.

ObservablePropertyChange  
using System.ComponentModel;  
using System.Runtime.CompilerServices;  
  
namespace UMSTasks  
{  
   public class ObservablePropertyChange : INotifyPropertyChanged  
   {  
	  public event PropertyChangedEventHandler PropertyChanged;  
	  protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")  
	  {  
		 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));  
	  }  
   }  
}  
  

StatusViewModel  
public class StatusViewModel :  ObservablePropertyChange   
   {  
	  #region Variables  
	  private bool _IsConnectedToServer = false;	   
	  public bool ConnectedToServer {  
		 get { return _IsConnectedToServer; }  
		 set {  
			   if (value != _IsConnectedToServer)  
				  { this._IsConnectedToServer = value;  
					 NotifyPropertyChanged();  
			   }			   
		 }	  
	  }  
	  		  
	  #endregion  
  
	  public StatusViewModel()  
	  {  
		 TestServerConnection();  
	  }  
  
	  private void TestServerConnection()  
	  {  
		 var statusModel = new StatusModel();  
		 var pingTestSuccess = statusModel.ServerPing();  
		 var taskSvcTestSuccess = statusModel.TaskServiceConnected();  
  
		 if (pingTestSuccess & taskSvcTestSuccess)  
		 {  
			ConnectedToServer = true;	  
						  
		 }  
  
	  }// private void TestServerConnection()  
  
	    
   }// public class StatusViewModel : EventArgs  
}  

StatusControl  
public partial class StatusControl : UserControl  
   {  
	  #region Variables  
  
	  public string _serverName = "";  
	  internal string _userName = null;  
	  internal string _pwd = null;  
	  internal const string domain = "COL";  
	  StatusViewModel svm = new StatusViewModel();  
	  #endregion  
	  //ctor  
	  public StatusControl()  
	  {  
		 InitializeComponent();  
  
		 this.DataContext = svm;  
		 svm.PropertyChanged += UpdateLED;  
		   
	  }  
  
	  //StatusViewModel event is true  
	  public void UpdateLED(object sender, PropertyChangedEventArgs e )  
	  {  
		 if (e.Equals(true))  
		 {  
			LED.Style = (Style)Application.Current.FindResource("GreenLED");  
						  
		 }else { LED.Style = (Style)Resources["RedLED"]; }  
		   
	  }  
  
  
   }// public partial class StatusControl : UserControl  
}  
  
Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,784 questions
XAML
XAML
A language based on Extensible Markup Language (XML) that enables developers to specify a hierarchy of objects with a set of properties and logic.
814 questions
{count} votes

Accepted answer
  1. Hui Liu-MSFT 48,571 Reputation points Microsoft Vendor
    2022-03-09T03:04:19.003+00:00

    Modify EllipseStyle.xaml according to your latest code and add the code.
    MainWidnow.xaml:

      <StackPanel>  
            <local:EllipseControl/>  
            <Button Grid.Row="1" Grid.Column="3"  Content="click" Width="100" Height="50" Click="Button_Click"/>  
        </StackPanel>  
    

    MainWindow.xaml.cs:

    public partial class MainWindow : Window  
        {  
            EllipseViewModel vm = new EllipseViewModel();  
            public MainWindow()  
            {  
                InitializeComponent();  
                DataContext = vm;  
            }  
            private void Button_Click(object sender, RoutedEventArgs e)  
            {  
                if (vm.ServerConnected)  
                {  
                    vm.ServerConnected = false;  
                }  
                else  
                {  
                    vm.ServerConnected = true;  
                }  
            }  
        }  
    

    EllipseStyle.xaml:

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">  
        <Style x:Key="StyleLED" TargetType="{x:Type Ellipse}" >  
            <Setter Property="Height" Value="20" />  
            <Setter Property="Width" Value="20" />  
            <Setter Property="Stroke" Value="DarkBlue" />  
            <Setter Property="StrokeThickness" Value="1" />  
            <Setter Property="Fill">  
                <Setter.Value>  
                    <RadialGradientBrush Center="0.3,0.3" Opacity="1">  
                        <RadialGradientBrush.GradientStops>  
                            <GradientStop Color="LightSalmon" Offset=".05"/>  
                            <GradientStop Color="Red" Offset=".95"/>  
                        </RadialGradientBrush.GradientStops>  
                    </RadialGradientBrush>  
                </Setter.Value>  
            </Setter>  
            <Style.Triggers>  
                <DataTrigger Binding="{Binding Path=ServerConnected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="true">  
                    <Setter  Property="Fill">  
                        <Setter.Value>  
                            <RadialGradientBrush Center="0.3,0.3" Opacity="1">  
                                <RadialGradientBrush.GradientStops>  
                                    <GradientStop Color="LightGreen" Offset=".05"/>  
                                    <GradientStop Color="Green" Offset=".95"/>  
                                </RadialGradientBrush.GradientStops>  
                            </RadialGradientBrush>  
                        </Setter.Value>  
                    </Setter>  
                </DataTrigger>  
            </Style.Triggers>  
        </Style>  
    </ResourceDictionary>  
    

    The result:
    181200-2.gif


    If the response is helpful, please click "Accept Answer" and upvote it.
     Note: Please follow the steps in our [documentation][5] to enable e-mail notifications if you want to receive the related email notification for this thread. 

    [5]: https://learn.microsoft.com/en-us/answers/articles/67444/email-notifications.html

    0 comments No comments

9 additional answers

Sort by: Most helpful
  1. vzmon1 41 Reputation points
    2022-02-22T12:57:16.157+00:00

    @Hui Liu-MSFT
    Below is the ClassModel, which I use to confirm connectivity to the server. Executing this portion provides the expected results, and I'm able to have a "true" value in the bool "ConnectedToServer" property in StatusViewModel class.

    StatusModel Class

    public class StatusModel : Control  
       {   
    	  #region Variables  
    	  private bool IsPingSuccess;  
    	  private bool IsTaskServiceConnected;  
    	  private string _serverName;  
    	  private string _userName;  
    	  private string _pwd;  
    	  private string _domain = "col";  
    	  public string _tasksvc = "service";  
      
    	    
    	  #endregion  
      
    	  //ctor  
    	  public StatusModel()  
    	  {  
    		 CustomSection customSection = ConfigurationManager.GetSection("CustomSettings") as CustomSection;  
    		 _serverName = COLENC06.EncodingManager.Decode(customSection.Server.value);  
    		 _userName = COLENC06.EncodingManager.Decode(customSection.SysID.value);  
    		 _pwd = COLENC06.EncodingManager.Decode(customSection.SysPass.value);  
      
    	  }//ctor  
      
      
    	  internal bool TaskServiceConnected()  
    	  {  
    		 var taskService = new TaskScheduler.TaskScheduler();  
    		 taskService.Connect(_serverName, _userName, _domain, _tasksvc);  
    		 if (taskService.Connected)  
    		 {  
    			return IsTaskServiceConnected = true;  
    		 }  
    		 else { return IsTaskServiceConnected; }  
      
    	  }  
      
    	  internal bool ServerPing()  
    	  {  
    		 var ping = new Ping();  
    		 var serverReply = ping.Send(_serverName, 60 * 500);  
      
    		 if (serverReply.Status.Equals(IPStatus.Success))  
    		 {  
    			return IsPingSuccess = true;  
    		 }  
    		 else { return IsPingSuccess; }  
      
    	  }  
      
       }  
    
    0 comments No comments

  2. vzmon1 41 Reputation points
    2022-02-24T14:13:01.087+00:00

    @Hui Liu-MSFT
    Thank you for the guidance, as I continued to research and test I started to circle back to perhaps using a DP property with Style triggers; your code will come in handy. Note that I can manually kick off the style change after validating my successful connection to the server.

    In my testing (this may be my wpf naivete), it looks like the PropertyChangedEventHandler is always null from the moment it's instantiated to when it's available in the StatusControl class, see attached png.177389-propertychanged.png

    Because of the empty Property Changed Event Handler, I thought that perhaps that I was invoking the change in the wrong place, but attempting to invoke the process from the Status Control class provided the same results. Hopefully with your code snippet I can re-think my approach to have better results.


  3. vzmon1 41 Reputation points
    2022-02-22T16:16:45.843+00:00

    @@Hui Liu-MSFT

    Resource Dictionary

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
                        xmlns:local="clr-namespace:UMSTasks.Resources">  
        <Style  TargetType="{x:Type Window}" x:Name="TargetWindowTheme" x:Key="WindowTheme" >  
            <Setter Property="Background" Value="#2b5797"/>  
            <Setter Property="FontFamily" Value="Calibri" />  
            <Setter Property="FontSize" Value="12" />  
            <Setter Property="Opacity" Value="10" />  
        </Style>  
        <Style TargetType="{x:Type TabControl}" x:Name="TabCtrlTheme" x:Key="TabControlTheme" >  
            <Setter Property="Background" Value="AliceBlue" />  
            <Setter Property="FontFamily" Value="Calibri" />  
            <Setter Property="FontSize" Value="11" />  
            <Setter Property="FontWeight" Value="Bold" />  
            <Setter Property="Margin" Value="2" />  
            <Setter Property="BorderBrush" Value="#2b5797" />  
            <Setter Property="BorderThickness" Value="1" />  
        </Style>  
        <Style x:Key="GreenLED" TargetType="{x:Type Ellipse}">  
            <Setter Property="Height" Value="20" />  
            <Setter Property="Width" Value="20" />  
            <Setter Property="Stroke" Value="DarkBlue" />  
            <Setter Property="StrokeThickness" Value="1" />  
            <Setter Property="Fill">  
                <Setter.Value>  
                    <RadialGradientBrush Center="0.3,0.3" Opacity="1">  
                        <RadialGradientBrush.GradientStops>  
                            <GradientStop Color="LightGreen" Offset=".05"/>  
                            <GradientStop Color="Green" Offset=".95"/>  
                        </RadialGradientBrush.GradientStops>  
                    </RadialGradientBrush>  
                </Setter.Value>  
            </Setter>  
        </Style>  
        <Style x:Key="RedLED" TargetType="{x:Type Ellipse}">  
            <Setter Property="Height" Value="20" />  
            <Setter Property="Width" Value="20" />  
            <Setter Property="Stroke" Value="DarkBlue" />  
            <Setter Property="StrokeThickness" Value="1" />  
            <Setter Property="Fill">  
                <Setter.Value>  
                    <RadialGradientBrush Center="0.3,0.3" Opacity="1">  
                        <RadialGradientBrush.GradientStops>  
                            <GradientStop Color="LightSalmon" Offset=".05"/>  
                            <GradientStop Color="Red" Offset=".95"/>  
                        </RadialGradientBrush.GradientStops>  
                    </RadialGradientBrush>  
                </Setter.Value>  
            </Setter>  
        </Style>  
    </ResourceDictionary>  
    
    0 comments No comments

  4. Hui Liu-MSFT 48,571 Reputation points Microsoft Vendor
    2022-02-24T10:14:53.337+00:00

    I modified the LED's Style as follows and used Button to simulate the ConnectedToServer connection. You could try to refer to the code below.
    UserControl.xaml:

    <Style x:Key="StyleLED" TargetType="{x:Type Ellipse}">  
                <Setter Property="Height" Value="20" />  
                <Setter Property="Width" Value="20" />  
                <Setter Property="Stroke" Value="DarkBlue" />  
                <Setter Property="StrokeThickness" Value="1" />  
                <Setter Property="Fill">  
                    <Setter.Value>  
                        <RadialGradientBrush Center="0.3,0.3" Opacity="1">  
                            <RadialGradientBrush.GradientStops>  
                                <GradientStop Color="LightSalmon" Offset=".05"/>  
                                <GradientStop Color="Red" Offset=".95"/>  
                            </RadialGradientBrush.GradientStops>  
                        </RadialGradientBrush>  
                    </Setter.Value>  
                </Setter>  
                <Style.Triggers>  
                    <DataTrigger Binding="{Binding Path=ConnectedToServer ,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Value="true">  
                        <Setter Property="Fill">  
                            <Setter.Value>  
                                <RadialGradientBrush Center="0.3,0.3" Opacity="1">  
                                    <RadialGradientBrush.GradientStops>  
                                        <GradientStop Color="LightGreen" Offset=".05"/>  
                                        <GradientStop Color="Green" Offset=".95"/>  
                                    </RadialGradientBrush.GradientStops>  
                                </RadialGradientBrush>  
                            </Setter.Value>  
                        </Setter>  
                    </DataTrigger>  
                </Style.Triggers>  
            </Style>  
    
    <Grid Height="150" Margin="0.5" x:Name="statusPanelGrid">  
                <Grid.ColumnDefinitions>  
                    <ColumnDefinition Width="2" ></ColumnDefinition>  
                    <ColumnDefinition Width="*"></ColumnDefinition>  
                    <ColumnDefinition Width="*"></ColumnDefinition>  
                    <ColumnDefinition Width="*"></ColumnDefinition>  
                    <ColumnDefinition Width="*"></ColumnDefinition>  
                    <ColumnDefinition Width="*"></ColumnDefinition>  
                    <ColumnDefinition Width="*"></ColumnDefinition>  
                    <ColumnDefinition Width="*"></ColumnDefinition>  
                    <ColumnDefinition Width="*"></ColumnDefinition>  
                    <ColumnDefinition Width="*"></ColumnDefinition>  
                </Grid.ColumnDefinitions>  
                <Grid.RowDefinitions>  
                    <RowDefinition Height="25"/>  
                    <RowDefinition Height="55"/>  
                    <RowDefinition Height="55"/>  
                </Grid.RowDefinitions>  
                <TextBlock x:Name="ConnectionLabel" Grid.Column="1" Grid.ColumnSpan="2"  
    Margin="0,0,5,0" HorizontalAlignment="Right" Height="15">  
     Server Connection  
                </TextBlock>  
                <Ellipse  x:Name="cp" Style="{DynamicResource  StyleLED}" Grid.Column="3" Margin="1" HorizontalAlignment="Left"  
    VerticalAlignment="Center" />  
                <Button Grid.Row="1" Grid.Column="3"  Content="click" Width="100" Height="50" Click="Button_Click"/>  
            </Grid>  
    

    MainWindow.xaml:

    <StackPanel>  
            <local:StatusControl   Height="200"/>  
        </StackPanel>  
    

    UserControl.xaml.cs:

    The result:
    177486-4.gif


    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.