I have a simple object (which is globally initiated in App.xaml.cs):
public class now_playing : INotifyPropertyChanged
{
// notify
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string p)
{
Debug.WriteLine(p + ": notify propertychanged");
PropertyChangedEventHandler handler = PropertyChanged;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
// artist
public string artist
{
get
{
return _artist;
}
set
{
_artist = value;
NotifyPropertyChanged("artist");
}
}
private string _artist;
// album
public string album
{
get
{
return _album;
}
set
{
_album = value;
NotifyPropertyChanged("album");
}
}
private string _album;
// track title
public string tracktitle
{
get
{
return _tracktitle;
}
set
{
_tracktitle = value;
NotifyPropertyChanged("tracktitle");
}
}
private string _tracktitle;
}
Whenever I change the values, the class does notify (I see the debug).
So I guess the problems lies in my XAML or the code behind.
Page code:
public sealed partial class nowplaying : Page
{
// artistdata
public string artist { get { return App.nowplaying.artist; } }
// albumdata
public string album { get { return App.nowplaying.album; } }
// trackdata
public string tracktitle { get { return App.nowplaying.tracktitle; } }
public nowplaying()
{
this.InitializeComponent();
this.DataContext = this;
}
}
XAML:
<Grid Margin="50">
<TextBlock Text="{Binding tracktitle}" Foreground="White" FontSize="40"/>
<TextBlock Foreground="#dcdcdc" FontSize="20" Margin="0,50,0,0">
<Run Text="{Binding artist}"/>
<Run Text=" - "/>
<Run Text="{Binding album}"/>
</TextBlock>
</Grid>
Why does the UI not update when I change values?
Stack trace:
Music.exe!Music.App.InitializeComponent.AnonymousMethod__6(object sender = {Music.App}, Windows.UI.Xaml.UnhandledExceptionEventArgs e = {Windows.UI.Xaml.UnhandledExceptionEventArgs}) Line 50 C#
Music.exe!play_music.MessageReceivedFromBackground(object sender = null, Windows.Media.Playback.MediaPlayerDataReceivedEventArgs e = {Windows.Media.Playback.MediaPlayerDataReceivedEventArgs}) Line 57 C#
UPDATE: problem solved! I had to use a dispatcher when calling the propertychanged event:
CoreDispatcher dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
if (PropertyChanged != null)
{
await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
this.PropertyChanged(this, new PropertyChangedEventArgs(p));
});
}
You "loose" the change notification in the properties in the Page as these properties do not have any change notifiaction.
Try using now_playing directly:
public sealed partial class nowplaying : Page
{
public now_playing NowPlaying { get { return App.nowplaying; } }
public nowplaying()
{
this.InitializeComponent();
this.DataContext = this;
}
}
and
<Run Text="{Binding NowPlaying.artist}"/>
Otherwise you need to implement INotifiyPropertyChanged in nowplaying and forward the events from now_playing.
You actually binding to artist, album and tracktitle Of nowplaying class which does implement INotifyPropertyChanged
Related
I am trying to move from WinForms to WPF, and am stuck on binding.
I have a label:
<Label Name="labelState" Content="{Binding state}" HorizontalAlignment="Right" Margin="10,10,10,10" FontSize="12" />
In the cs of the same userControl (named FormInput), I have :
public string state { get; set; }
public FormInput()
{
state = "ok";
InitializeComponent();
}
Why doesn't this work?
Thank you.
When you are binding something in WPF you need to use INotifyPropertyChanged
Implement a class follows,
class TestObject : INotifyPropertyChanged
{
private string _state;
public string State
{
get
{
return _state;
}
set
{
if (_state == value) return;
_state = value;
OnPropertyChanged("State");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
and in your FormInput
public FormInput()
{
InitializeComponent();
TestObject t = new TestObject();
labelState.DataContext = t;
t.State = "ok";
}
and XAML as follows,
<Label Name="labelState" Content="{Binding State}" HorizontalAlignment="Right" >
this my xml code
<TextBlock Grid.Column="0" Tag="{Binding id,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Text="{Binding Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
this is my model
public string _Name;
public string Name
{
get { return _Name; }
set { _Name = value; RaisePropertyChanged("Name"); }
}
when i set value to these two propertie ie. to id and Name
but its not notifying to Name ...
Simple Databinding Example with Updates. You can use this as a reference to get you started :)
public partial class MainWindow : Window, INotifyPropertyChanged
{
// implement the INotify
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
private string _mytext;
public String MyText
{
get { return _mytext; }
set { _mytext = value; NotifyPropertyChanged("MyText"); }
}
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = this; // set the datacontext to itself :)
MyText = "Change Me";
}
}
<TextBlock Text="{Binding MyText}" Foreground="White" Background="Black"></TextBlock>
I'm trying to bind a string property to show in my status bar if my database is connected. Here's the code:
C#
public class TimeBase : INotifyPropertyChanged
{
private DXTickDB db;
string[] args = new string[] { };
public event PropertyChangedEventHandler PropertyChanged;
private bool isTBconnected;
public string connectionStatus { get; set; }
public bool tb_isconnected
{
get { return isTBconnected; }
set
{
if (value != isTBconnected)
{
isTBconnected = value;
if(isTBconnected == false)
{
connectionStatus = "TimeBase is not connected";
}
else
{
connectionStatus = "TimeBase is connected";
}
OnPropertyChanged("connectionStatus");
}
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#region TimeBase Connection
public void ConnectToTimeBase()
{
if (args.Length == 0)
args = new string[] { "not available for security reasons" };
db = TickDBFactory.createFromUrl(args[0]);
try
{
db.open(true);
tb_isconnected = true;
}
catch
{
tb_isconnected = false;
}
}
#endregion
This is the Xaml for the status bar in my main window:
<StatusBar Height="23" DockPanel.Dock="Bottom" Background="Green">
<StatusBarItem>
<StackPanel Orientation="Horizontal">
<TextBlock
Foreground="{StaticResource Foreground}"
Text="{Binding Path=connectionStatus}">
</TextBlock>
</StackPanel>
</StatusBarItem>
</StatusBar>
I'm trying to bind it to the string property connectionStatus but no text appears even though when I debug it I can see connectionStatus updated. Any suggestions to what's wrong here?
DataContext property should contain your model like so:
TimeBase timeBaseInstance;
public MainWindow()
{
timeBaseInstance = new TimeBase();
//Set the dataContext so bindings can iteract with your data
DataContext = timeBaseInstance;
InitializeComponent();
}
I am having a difficult time getting my WPF to properly use Databinding. In the XAML I have a the following:
....
<TextBox Name="txt_FirstName" Text="{Binding Path=currentApplication.FirstName, UpdateSourceTrigger=PropertyChanged}" />
....
I have in the following CS code:
namespace WPF1
{
public partial class MainWindow : Window
{
personalApp currentApplication = new personalApp ();
public MainWindow()
{
InitializeComponent();
}
}
}
That references the following two classes:
class personalApp : INotifyPropertyChanged
{
private Person person = new Person();
public string FirstName
{
get { return person.FirstName; }
set
{
person.FirstName = value;
this.OnPropertyChanged("FirstName");
}
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(
this, new PropertyChangedEventArgs(propName));
}
}
class Person
{
private string firstName = "";
get { return firstName; }
set { FirstName = value; }
}
I pause it in the code and step through to check, but when I update the txt_FirstName in the application, it never seems to set the firstName Object.
Where am I going wrong?
You need to update your XAML binding, and set the DataContext of the Window using the TextBox.
namespace WPF1
{
public partial class MainWindow : Window
{
personalApp currentApplication = new personalApp ();
public MainWindow()
{
InitializeComponent();
this.DataContext = currentApplication;
}
}
}
Updating the XAML:
<TextBox Name="txt_FirstName" Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged}" />
I have corrected the code.
For text box:
<TextBox Name="txt_FirstName" Height="30" Background="Beige"
Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}" />
C# Code
namespace Wpf1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new personalApp();
}
}
internal class personalApp : INotifyPropertyChanged
{
private Person person = new Person();
public string FirstName
{
get { return person.FirstName; }
set
{
person.FirstName = value;
this.OnPropertyChanged("FirstName");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(
this, new PropertyChangedEventArgs(propName));
}
}
internal class Person
{
public string FirstName { get; set; }
}
}
public MainWindow()
{
DataContext = this;
InitializeComponent();
}
or if you don't want to assign data context to yourself (window), as you might have other datacontext coming into the window, you can add this in xaml:
give your window a name:
<Window .... x:Name="this"...
then
<TextBox Name="txt_FirstName" Text="{Binding ElementName=this,
Path=currentApplication.FirstName/>
What you mean by "update the txt_FirstName in the application" ?
If you set directly the value of the textbox then you should try to set the value of currentApplication instead of the textbox value
I have a problem with my Binding to a ListBox Control.
Actually i have a Property in App.xaml.cs :
public partial class App : Application, INotifyPropertyChanged
{
ObservableCollection<Panier> _panier = new ObservableCollection<Panier>();
public ObservableCollection<Panier> PanierProperty
{
get { return _panier; }
set
{
if (this._panier != value)
{
this._panier = value;
NotifyPropertyChanged("PanierProperty");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
this property have a child properties in the "Panier class" here:
public class Panier : INotifyPropertyChanged
{
private string _nom;
private string _category;
private int _prix;
public string Nom
{
get { return _nom; }
set
{
if (this._nom != value)
{
this._nom = value;
NotifyPropertyChanged("Nom");
}
}
}
public string Category
{
get { return _category; }
set
{
if (this._category != value)
{
this._category = value;
NotifyPropertyChanged("Category");
}
}
}
public int Prix
{
get { return _prix; }
set
{
if (this._prix != value)
{
this._prix = value;
NotifyPropertyChanged("Prix");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
and in my MainWindow.xaml page i have my ListBox bound to PanierProperty(parent property) :
<telerik:RadListBox x:Name="PanierLB" Grid.Row="1" Height="200" Width="350" Margin="0 300 0 0"
ItemsSource="{Binding PanierProperty, Source={x:Static Application.Current}}"
DisplayMemberPath="{Binding Path=PanierProperty.Nom, Source={x:Static Application.Current}}">
</telerik:RadListBox>
my problem is that PanierProperty is bound to my Listbox i see items in the listbox like Design.Panier
Design.Panier
Design.Panier
etc...
I dont know how to get the PanierProperty.Nom(Nom is the child property) to show on the ListBox.
Someone can help please.
In DisplayMemberPath use the name of property you want to show only:
<telerik:RadListBox
...
DisplayMemberPath="Nom"