WPF- Binding a TextBlock to a Button - c#

The same questions has been asked many times on this site and I have read most of them. But I have a special problem (maybe?) that couldn't figure it out after hours of struggling and reading SO posts.
The problem is -simply explained, I have a WPF form which contains a Connect button. If this button is pressed a textblock must appear on that form, displaying the word "Connecting...". Upon pressing the button, some handshaking operations are done in the associated C# code which takes some time. If the program fails to connect, the textblock must change to "Failed!". Otherwise, it changes to "Succeed."
Now for this simple problem, I wrote in my XAML:
<Window x:Class="WpfTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="300" Width="200">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Button x:Name="connecting" Content="Connect" FontWeight="Bold" Click="startConnection"
Width="60" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="0"/>
<TextBlock x:Name="comm_stat" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"
Text="{Binding Content}"/>
</Grid>
</Window>
And the C# code (inspired by this answer):
using System;
using System.Text;
using System.Windows;
using System.ComponentModel;
namespace WpfTest
{
public class DynamicObj : INotifyPropertyChanged
{
public DynamicObj() : this(string.Empty) { }
public DynamicObj(string txt) { Content = txt; }
private string _name;
public string Content
{
get { return _name; }
set {
_name = value;
OnPropertyChanged("Content");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string PropertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
comm_stat.DataContext = new DynamicObj();
}
private void startConnection(object sender, RoutedEventArgs e)
{
comm_stat.Text = "Connecting...";
bool connect2device = false;
// do the handshaking operations. the result is then assigned to connect2device
comm_stat.Text = connect2device ? "Succeed." : "Failed!";
// some other operations
}
}
}
Now the problem is, whenever I click the button, no text is appeared in the textblock. Because the program waits for the startConnection method to reach its end and then updates the bonded textblock. But I want the textblock to change right after pressing the button. How can I do this?

You can use BackgroundWorker as such:
bool connect2device = false;
private void startConnection(object sender, RoutedEventArgs e)
{
comm_stat.Text = "Connecting...";
// do the handshaking operations. the result is then assigned to connect2device
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += DoWork;
worker.RunWorkerCompleted += Completed;
worker.RunWorkerAsync();
}
private void Completed(object sender, RunWorkerCompletedEventArgs e)
{
comm_stat.Text = connect2device ? "Succeed." : "Failed!";
}
private void DoWork(object sender, DoWorkEventArgs e)
{
//Change with actual work.
Thread.Sleep(1000);
connect2device = true;
}
One side note is that you actually do not use bindings to change the text. comm_stat.Text = "Connecting..."; sets the text property directly and the DynamicObj object is not used at all. It might be good for you to read a few tutorial on MVVM.

Related

Raise a event on the User control from the Main Window in WPF

There is a textbox in my mainwindow.xaml, when I enter the textbox, I expect the label in my usercontrol, known as View1.xaml will be update accordingly. However I realise the event is not raise at all in the user control when I type the textbox, can you tell me which part is wrong?
The event is able to raise in TextBox_TextChanged_1
my MainWindow.XAML
<Window xmlns:my="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:testapplication" x:Class="testapplication.MainWindow"
Title="MainWindow" Height="964" Width="790">
<Grid >
<Button x:Name="OpenView1" Content="Open Window 1" HorizontalAlignment="Left" Margin="33,70,0,0" VerticalAlignment="Top" Width="111" RenderTransformOrigin="0.279,1.409" Click="OpenView1_Click"/>
<Button x:Name="OpenView2" Content="Open Window 2" HorizontalAlignment="Left" Margin="33,169,0,0" VerticalAlignment="Top" Width="111" Click="OpenView2_Click"/>
<Button x:Name="OpenView3" Content="Open Window 3" HorizontalAlignment="Left" Margin="33,259,0,0" VerticalAlignment="Top" Width="111" Click="OpenView3_Click"/>
<local:View1 x:Name="ViewOne" HorizontalAlignment="Left" Margin="33,332,0,0" VerticalAlignment="Top" Height="226" Width="204" Visibility="Hidden"/>
<local:View2 x:Name="ViewTwo" HorizontalAlignment="Left" Margin="284,332,0,0" VerticalAlignment="Top" Height="226" Width="208" Visibility="Hidden"/>
<local:View3 x:Name="ViewThree" HorizontalAlignment="Left" Margin="534,332,0,0" VerticalAlignment="Top" Height="226" Width="196" Visibility="Hidden"/>
<TextBox HorizontalAlignment="Left" Height="42" Margin="326,70,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="182" FontSize="22" TextChanged="TextBox_TextChanged_1"/>
</Grid>
</Window>
my MainWindow.cs
namespace testapplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
//InitializeComponent();
}
//event handler
public event EventHandler<EventArgs> changedText;
private void OpenView1_Click(object sender, RoutedEventArgs e)
{
ViewOne.Visibility = Visibility.Visible;
}
private void OpenView2_Click(object sender, RoutedEventArgs e)
{
ViewTwo.Visibility = Visibility.Visible;
}
private void OpenView3_Click(object sender, RoutedEventArgs e)
{
ViewThree.Visibility = Visibility.Visible;
}
private void TextBox_TextChanged_1(object sender, TextChangedEventArgs e)
{
if (changedText != null)
{
changedText(this, e);
}
}
}
}
This is my UserControl, known as View1.xaml, it is included in my MainWindow.Xaml
namespace testapplication
{
/// <summary>
/// Interaction logic for View1.xaml
/// </summary>
public partial class View1 : UserControl
{
private MainWindow newWindow = new MainWindow();
public View1()
{
InitializeComponent();
newWindow.changedText += newWindow_ChangeText;
}
void newWindow_ChangeText(object sender, EventArgs e)
{
ViewOnelabel.Content = "Happy";
}
}
}
The problem is my ViewOnelabel.Content = "Happy" did not execute at all, it remain unchanged
There are a few things I would like to point out.
The equivalent of a winforms label in wpf is a TextBlock. A wpf label is actually a type of contentcontrol. Hence the content property.
In wpf there are routed events. These "bubble" up ( and tunnel down ) the visual tree. That means you can handle an event in the window from a control in a usercontrol inside it.
But mainly.
I encourage you to look into the MVVM pattern.
I've put together some code which illustrates these points.
I'd recommend just using binding and mvvm though.
My MainWindow markup:
Title="MainWindow" Height="350" Width="525"
TextBoxBase.TextChanged="Window_TextChanged"
>
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<StackPanel>
<Label Name="OutputLabel"/>
<TextBlock Text="{Binding OutputString}"/>
<local:UserControl1/>
</StackPanel>
</Grid>
Notice that it handles a textchanged event and because that's routing it will get the event from UserControl1 inside it.
Code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_TextChanged(object sender, TextChangedEventArgs e)
{
OutputLabel.Content = $"Happy {((TextBox)e.OriginalSource).Text}";
}
}
You don't do anything with the text from your textbox in your handler but I have some code there proves you could get at that from mainwindow if you wanted.
My viewmodel:
public class MainWindowViewModel : INotifyPropertyChanged
{
private string inputString;
public string InputString
{
get { return inputString; }
set
{
inputString = value;
OutputString = $"{inputString.Length} characters entered";
RaisePropertyChanged();
}
}
private string outputString;
public string OutputString
{
get { return outputString; }
set
{
outputString = value;
RaisePropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Usercontrol1 just has a textbox:
<Grid>
<TextBox Text="{Binding InputString, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
As you type in that textbox, the text is transferred to the bound property in my viewmodel. That hits the code in my setter. This in turn sets OutputString which is bound to my textblock.
Text changes in both my label and textblock as I type.
Here's a link to my sample on onedrive
https://1drv.ms/u/s!AmPvL3r385QhgpgOPNKPs-veFJ2O3g
The main problem here is that your View1 class is subscribing to an event on a new MainWindow instance, not the MainWindow instance created by your application on start.
Since your MainWindow class has a reference to your View1 class (a named member "ViewOne") you should just change it from the MainWindow class.
private void TextBox_TextChanged_1(object sender, TextChangedEventArgs e)
{
ViewOne.ViewOneLabel.Content = "Happy";
}
Get rid of the chenagedText event handler and all the code in the View1.xaml.cs... you don't need it.
Note: I am hoping that you are just playing around and learning here... there is no way I would condone building a WPF application in this way.
You could only use the event of the MainPage. I recomment you to add a Property to the UserControl. In my case I call it Text.
public string Text
{
set { ViewOneLabel.Content = value; }
}
In the MainWindow use the Property within the TextChanged Event.
private void TextBox_TextChanged_1(object sender, TextChangedEventArgs e)
{
OpenView1.Text = TextBox.Text;
}
You are creating a new instance of MainWindow in your UserControl. What you want to do is to hook up an event handler to the instance that you actually see on the screen. You can get a reference to this one using the Window.GetWindow method:
public partial class View1 : UserControl
{
public View1()
{
InitializeComponent();
Loaded += (s, e) =>
{
Window mainWindow = Window.GetWindow(this) as MainWindow;
if(mainWindow != null)
mainWindow.changedText += newWindow_ChangeText;
};
}
void newWindow_ChangeText(object sender, EventArgs e)
{
ViewOnelabel.Content = "Happy";
}
}

INotifyPropertyChanged - always null

My class "ship" should change value of property "ShipOnePos" continuously. This value is binded to one of UI element (image) property. I like to update my UI according to "ShipOnePos" (when it is changed). So for this reason I use interface INotifyPropertyChanged, but UI is not updating, and PropertyChanged value is always null.
Can You advice what I miss, or what is wrong in this implementation ?
Class:
namespace DzienNaWyscigach
{
public class ship : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private int MyShipOnePos;
public int ShipOnePos
{
get { return MyShipOnePos; }
set { MyShipOnePos = value;
NotifyPropertyChanged();
}
}
public void ShipsMovment()
{
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(500);
timer.Tick += Timer_Tick;
timer.Start();
}
private void Timer_Tick(object sender, EventArgs e)
{
ShipOnePos= ShipOnePos+10;
}
}
}
UI Binding
<Image x:Name="ShipOne" HorizontalAlignment="Left" Height="71" Margin="31,32,0,0" VerticalAlignment="Top" Width="80" Source="Asets/ship1.png" RenderTransformOrigin="0.5,0.5">
<Image.DataContext>
<local:ship/>
</Image.DataContext>
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform X="{Binding Path=ShipOnePos, Mode=OneWay}"/>
</TransformGroup>
</Image.RenderTransform>
Code behind
private void BTN_Start_Click(object sender, RoutedEventArgs e)
{
ship Ships = new ship();
Ships.ShipsMovment();
}
The ship you are creating in your click isn't the ship you bound your Image to. You should probably create a ship as a resource and in your Click event retrieve that existing ship and start it moving. Or else, you might want to have a parent VM with a ship property.
So for example, you could do something like this:
<Window.Resources>
<local:ship x:Key="myShip"/>
</Window.Resources>
....
<Image x:Name="ShipOne"
HorizontalAlignment="Left" Height="71"
Margin="31,32,0,0" VerticalAlignment="Top" Width="80" Source="Asets/ship1.png"
RenderTransformOrigin="0.5,0.5"
DataContext="{StaticResource myShip}">
...
</Image>
And then in your click handler:
private void BTN_Start_Click(object sender, RoutedEventArgs e)
{
// Note: it might be worth caching this in a field or property
ship Ships = FindResource("myShip") as ship;
Ships.ShipsMovment();
}
Or alternatively, using the parent VM idea:
public class ParentVM : INotifyPropertyChanged
{
private ship _currentShip;
public ship CurrentShip
{
get { return _currentShip; }
set { _currentShip = value; NotifyPropertyChanged(); }
}
// ....
}
And then you could do:
<Window.Resources>
<local:ParentVM x:Key="myVM"/>
</Window.Resources>
...
<Grid DataContext="{StaticResource myVM}">
....
<Image DataContext="CurrentShip" ...>
....
</Image>
</Grid>
And:
// Note: this might be better handled with a command rather than a click handler
private void BTN_Start_Click(object sender, RoutedEventArgs e)
{
// Note: it might be worth caching this in a field or property
ParentVM vm = FindResource("myVM") as ParentVM;
vm.CurrentShip = new ship();
vm.CurrentShip.ShipsMovment();
}

C# WPF Update Textbox on Property change

I got an Problem with updating the text in a Textbox. I got this MainWindow:
<Window x:Class="TestDatabinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="10,10,10,10"/>
<Button Grid.Row="1" Content="Click me" Margin="10,10,10,10" Click="Button_Click"></Button>
<Button Grid.Row="2" x:Name="a1" Content="ShowText" Margin="10,10,10,10" Click="a1_Click" ></Button>
</Grid>
Now the cs-file for this MainWindow looks like:
using System.Windows;
namespace TestDatabinding
{
public partial class MainWindow : Window
{
MainWindowViewModel mwvm;
public MainWindow()
{
InitializeComponent();
mwvm = new MainWindowViewModel();
this.DataContext = mwvm;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
mwvm.ChangeText();
this.DataContext = mwvm;
}
private void a1_Click(object sender, RoutedEventArgs e)
{
mwvm.showText();
}
}
}
And last but not least the ViewModel Class:
using System.ComponentModel;
using System.Windows;
namespace TestDatabinding
{
class MainWindowViewModel
{
public event PropertyChangedEventHandler PropertyChanged;
private string text;
public string Text
{
get { return this.text; }
set
{
this.text = value;
OnPropertyChanged("Text");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
public void ChangeText()
{
this.Text = "Hey paadddyy";
}
public void showText()
{
MessageBox.Show(Text);
}
}
}
I didn´t implement ICommands, because this is a simple test.
Now the Button's work correctly but the Textbox Text didn´t get updated.
Any suggestions what i can do? I only want to display "Hey paadddyy" when I click the first Button. After I press the second Button and then the first the MessageBox shows "Hey paadddyy" but the Textbox text didn´t get updated :(
Thank you for every hint ;)
Your MainWindowViewModel does not implement INotifyPropertyChanged. It needs to look like that:
class MainWindowViewModel: INotifyPropertyChanged
you define the event but does not implement the interface
It need to implement INotifyPropertyChanged
I suggested that if you want to do something with Notify Property. Another easy way is to apply Caliburn.Micro Framework to your project.
Follow this link.

Databinding and then calling from another class in WPF

My purpose is to add a textblock to my main UI window, of which text will be updated if needed. For that, in my UIWindow xaml I did like this:
<Window x:Class="UIDesigner.UIWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:UIDesigner"
xmlns:c="clr-namespace:UIDesigner.Controls"
WindowStartupLocation="CenterScreen"
WindowState="Maximized"
WindowStyle="SingleBorderWindow"
Title="GUI"
Height="1000" Width="1400"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Icon="Resources/Images/Logo.png"
>
<Grid Margin="0">
<Grid Grid.Row="1" Margin="0,10,0,0">
<GroupBox Header="Console" Grid.Column="1" Margin="0,590,0,0" HorizontalAlignment="Stretch" x:Name="consoleWindow" IsEnabled="True" VerticalAlignment="Stretch"
>
<TextBlock x:Name="myConsoleWindowTextBlock" Text="{Binding Path=consoleText}"/>
</GroupBox>
</Grid>
</Grid>
</Window>
This is the code behind:
using System.Windows;
using System.Runtime.CompilerServices;
using System.ComponentModel;
namespace UIDesigner
{
public partial class UIWindow : Window
{
public UIWindow()
{
InitializeComponent();
}
private string _consoleText;
public string consoleText
{
get{ return _consoleText;}
set
{
_consoleText = value;
NotifyPropertyChanged("consoleText");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
}
Then in my main class, I call this UIWindow like this:
namespace UIDesigner
{
public partial class Main : Window
{
public Main()
{
InitializeComponent();
}
private void LoginButton_Click_1(object sender, RoutedEventArgs e)
{
var myUIWindow = new UIWindow();
myUIWindow.PropertyChanged += new PropertyChangedEventHandler(UIWindow_PropertyChanged);
myUIWindow.consoleText = "Hello User!";
myUIWindow.ShowDialog();
this.Close();
}
private void LoginButton_MouseEnter_1(object sender, MouseEventArgs e)
{
}
static void UIWindow_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
MessageBox.Show("Something Changed!");
MessageBox.Show(e.PropertyName);
}
}
}
Now I have two problems here:
First, when my UI window starts, I indeed received two message boxes, saying "something changed" followed by "consoleText". So that means the consoleText is changed successfully. But after my UIWindow shows up, the textblock is empty, I cannot see "Hello User!" there. Seems like Text="{Binding Path=consoleText} part is not working correctly in my xaml file.
Second and most importantly, I want to change the consoleText in another different class, namely in DesignerCanvas.Commands.cs. For that I couldn't figure out any solution. I want something like this in my DesignerCanvas.Commands.cs:
namespace UIDesigner
{
public partial class DesignerCanvas
{
private void changeConsoleOutput(string updatedConsoleText)
{
myUIWindow.consoleText = updatedConsoleText; //obviously, this is not working
}
}
}
Any kind of suggestion will be much appreciated.
1.First of two set the value in UI just add below one line
in constructor of UIWindow class
this.DataContext=this;
//because only specifying property consoletext, it will not able to know where to find consoletext.
2.u can find that UIwindow in App.Current.Windows and cast it to UIWindow type and then can
access the property.
foreach(Window win in App.Current.Windows)
{
if (win as UIWindow != null)
{
(win as UIWindow).consoletext = updatedConsoleText;
}
}
For second problem
Change
<TextBlock x:Name="myConsoleWindowTextBlock" Text="{Binding Path=consoleText}"/
To
<TextBlock x:Name="myConsoleWindowTextBlock" Text="{Binding Path=.}"/
and
in UIWindow constructor set
myConsoleWindowTextBlock.Datacontext=consoleText;

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!
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:
Make Message into a Dependancy Property.
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:
Define the event PropertyChanged.
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.
In the property setter, call NotifyPropertyChanged with the correct name (case-sensitive) of the property after the value has changed.
Just replace your Message property like this and it will work:
public string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
public static readonly DependencyProperty MessageProperty =
DependencyProperty.Register("Message", typeof(string),
typeof(MainWindow), new UIPropertyMetadata(String.Empty));
EDIT after posting my solution I noticed you changed all the code into a ViewModel solution... feel free to ignore or go back to your first set of code.
In your new code you are creating TWO instances of the ViewModel, one in code and one in the resources. That is not good as you are manipulating the one in code and binding to the one in the resources(xaml)
EDIT:
change your constructor to this:
public MainWindow()
{
InitializeComponent();
stopwatch = new StopWatchViewModel();
this.DataContext = stopwatch;
}
That's all
Changes to the property won't get noticed if you don't implement INotifyPropertyChanged correctly. So you should do that first. Maybe you missed something when you did it earlier.

Categories