I am absolute beginner in WPF and C#. I am trying to populate the textbox with a counter after reading about INotifyPropertyChanged.
Below is my code:
namespace DataBinding
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
///
//https://learn.microsoft.com/en-us/dotnet/desktop/wpf/data/how-to-implement-property-change-notification?view=netframeworkdesktop-4.8
public class OPCUAData : INotifyPropertyChanged
{
private string m_text;
private int m_int;
public event PropertyChangedEventHandler PropertyChanged;
public OPCUAData()
{ }
public OPCUAData(string str, int i)
{
this.m_text = str;
this.m_int = i;
}
public string OPCUAtext
{
get { return m_text; }
set
{
if (value != m_text)
{
m_text = value;
OnPropertyChanged();
}
}
}
public int OPCUAint
{
get { return m_int; }
set
{
if (value != m_int)
{
m_int = value;
OnPropertyChanged();
}
}
}
// Create the OnPropertyChanged method to raise the event
// The calling member's name will be used as the parameter.
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
public partial class MainWindow : Window
{
static OPCUAData opc = new OPCUAData("", 5);
public MainWindow()
{
InitializeComponent();
Thread thread = new Thread(incrementData);
thread.Start();
}
void incrementData()
{
Stopwatch timer = new Stopwatch();
timer.Start();
while (timer.Elapsed.TotalSeconds < 10)
{
opc.OPCUAint = opc.OPCUAint 1;
}
timer.Stop();
}
}
}
I am expecting my variable opc.OPCUAint
to be displayed in the textbox but it is not. Please help about what I am missing here.
Below is the xml.
<Window x:Class="DataBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DataBinding"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TextBox Text="{Binding ElementName=opc, Path= OPCUAint }" Margin="91,56,454.6,286"></TextBox>
</Grid>
</Window>
CodePudding user response:
Set the DataContext
of your window:
public MainWindow()
{
InitializeComponent();
DataContext = opc; // <--
Thread thread = new Thread(incrementData);
thread.Start();
}
...and bind directly to a property of it:
<TextBox Text="{Binding OPCUAint}" />
CodePudding user response:
You need to make "opc" public property and modify the binding accordingly.
public OPCUAData opc { get; } = new OPCUAData("", 5);
<TextBox Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=opc.OPCUAint}"/>
CodePudding user response:
You use a StopWatch
to measure time.
You use a timer to execute an operation periodically.
For example use Timer
to execute the operation on a background thread or use DispatcherTimer
to execute the operation on the UI thread.
public void StartTimer()
{
// The callback will automatically execute on a background tread.
// Note that Timer implements IDisposable
var timer = new Timer(PeriodicOperation);
// Start the timer.
timer.Change(TimeSpan.Zero, TimeSpan.FromSeconds(1));
}
private void PeriodicOperation(object state)
{
opc.OPCUAint ;
}
If incrementing is the only operation, or you don't execute CPU intensive code in general, don't create a dedicated thread. It will make the performance unnecessarily bad. In this case, and in case of your posted example, use the mentioned DispatcherTimer
:
public void StartTimer()
{
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick = PeriodicOperation;
dispatcherTimer.Interval = TimeSpan.Fromseconds(1);
dispatcherTimer.Start();
}
private void PeriodicOperation(object sender, EventArgs e)
{
opc.OPCUAint ;
}
Then finally to make it work, you must assign the OPCUAData
instance to the DataContext
of the MainWindow
. Avoid defining public static fields or properties:
private OPCUAData OPCUAData { get; }
public MainWindow()
{
InitializeComponent();
this.OPCUAData = new OPCUAData("", 5);
this.DataContext = this.OPCUAData;
StartTimer();
}
public void StartTimer()
{
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick = PeriodicOperation;
dispatcherTimer.Interval = TimeSpan.Fromseconds(1);
dispatcherTimer.Start();
}
private void PeriodicOperation(object sender, EventArgs e)
{
this.OPCUAData.OPCUAint ;
}
And bind directly to the DataContext
:
<Window>
<TextBox Text="{Binding OPCUAint}" />
</Window>