Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple databinding not working

I'm new to WPF and I'm trying to make a simple app, a stopwatch. It works fine if I'm not doing the data binding. Here's my XAML.

<Window x:Class="StopWatch.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="clr-namespace:StopWatch"
    Title="MainWindow" Height="318" Width="233">
<Window.Resources>
    <s:StopWatchViewModel x:Key="swViewModel" x:Name="swViewModel"></s:StopWatchViewModel>
</Window.Resources>
<Grid DataContext="{StaticResource swViewModel}"> 
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="128*" />
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="1" Height="49" HorizontalAlignment="Left" Margin="42,50,0,0" Name="txtTime" Text="{Binding Path=Message}" VerticalAlignment="Top" Width="147" FontSize="20" TextAlignment="Center" />
    <Button Content="Start" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="12,15,0,0" Name="startBtn" VerticalAlignment="Top" Width="58" Click="startBtn_Click" />
    <Button Content="Stop" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="76,15,0,0" Name="stopBtn" VerticalAlignment="Top" Width="58" Click="stopBtn_Click" />
    <Button Content="Reset" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="140,15,0,0" Name="resetBtn" VerticalAlignment="Top" Width="59"/>
</Grid>

and here is the code in MainWindow

public partial class MainWindow : Window
{
    private StopWatchViewModel stopwatch;

    public MainWindow()
    {
        InitializeComponent();
        stopwatch = new StopWatchViewModel();
    }

    private void startBtn_Click(object sender, RoutedEventArgs e)
    {
        stopwatch.Start();
    }

    private void stopBtn_Click(object sender, RoutedEventArgs e)
    {
        stopwatch.Stop();
    }
}

and here's the code in StopWatchViewModel.cs

class StopWatchViewModel : INotifyPropertyChanged
{
    private DispatcherTimer timer;
    private Stopwatch stopwatch;
    private string message;

    public event PropertyChangedEventHandler PropertyChanged;

    public string Message
    {
        get
        {
            return message;
        }
        set
        {
            if (message != value)
            {
                message = value;
                OnPropertyChanged("Message");
            }
        }
    }

    public StopWatchViewModel()
    {
        timer = new DispatcherTimer();
        stopwatch = new Stopwatch();
        timer.Tick += new EventHandler(timer_Tick);
        timer.Start();
        stopwatch.Reset();
    }

    public void Start()
    {
        stopwatch.Start();
    }

    public void Stop()
    {
        stopwatch.Stop();
    }

    private void timer_Tick(object sender, EventArgs e)
    {
        Message = stopwatch.Elapsed.ToString(); // Doesn't work.
        // Message = "hello"; does not work too!
    }

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

}

I don't know where I got it wrong.

EDIT: I got it working. So here's the working code for anyone's reference.

XAML, change the original to this

<Window x:Class="StopWatch.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:StopWatch"
Title="MainWindow" Height="318" Width="233">
<Grid> // partial code

and in behind code, change the constructor based on Erno's suggestion.

public MainWindow()
    {
        InitializeComponent();
        viewModel = new StopWatchViewModel();
        this.DataContext = viewModel;
    }

Thanks guys!

like image 321
Shulhi Sapli Avatar asked Jun 23 '26 20:06

Shulhi Sapli


1 Answers

Your problem here is that you don't have any mechanism for letting WPF know that your property is updated. Basically you have two options here:

  1. Make Message into a Dependancy Property.
  2. Implement INotifyPropertyChanged so that it let's the GUI know when the message have been updated.

To make sure that you have all parts for getting INotifyPropertyChanged to work, check that you did all of this:

  1. Define the event PropertyChanged.
  2. Make a private NotifyPropertyChanged method to raise the event. This method should take a string parameter (name of the property) and raise the event like this : PropertyChanged(this, new PropertyChangedEventArgs(<nameofproperty>). The reason to make this method is to put the null check and invocation details in one place.
  3. In the property setter, call NotifyPropertyChanged with the correct name (case-sensitive) of the property after the value has changed.
like image 91
Øyvind Bråthen Avatar answered Jun 26 '26 10:06

Øyvind Bråthen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!