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>
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" >
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
I need Model to notify ViewModel if any property is changed, because I need to collect the changed model instances in a collection for further processing, also to enable and disable command buttons in the viewmodel.
So I've used ModelBase abstract class and added HasChanges property which I can test against in the viewmodel and catch the changed models.But it is not working and I don't know what i'm missing.
public abstract class ModelBase : INotifyPropertyChanged
{
protected ModelBase()
{
}
private bool _hasChanges;
public bool HasChanges
{
get
{
return _hasChanges;
}
set
{
if (_hasChanges != value)
{
_hasChanges = value;
RaisePropertyChanged("HasChanges");
}
}
}
protected void RaisePropertyChanged(string propertyName)
{
HasChanges = true;
this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, e);
}
}
}
The Model is wrapped inside the ViewModel and bound to the View which is a DataGrid:
private Model_selectedModel;
public Mode SelectedModel
{
get
{
return _selectedModel;
}
set
{
if (_selectedModel != value)
{
_selectedModel = value;
NotifyPropertyChanged("SelectedModel");
}
}
}
Thanks for valuable help.
I tested your class and it's okay. I think the point is a typo here:
private Model_selectedModel;
public Mode SelectedModel
{
get
{
return _selectedModel;
}
set
{
if (_selectedModel != value)
{
_selectedModel = value;
NotifyPropertyChanged("SelectedModel");
}
}
}
There should be RaisePropertyChanged instead of NotifyPropertyChanged.
Below it's my test:
XAML
<Window x:Class="TestUpdatePropertyChanged.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:this="clr-namespace:TestUpdatePropertyChanged"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<this:TestViewModel />
</Window.DataContext>
<Grid>
<TextBox Width="100" Height="25" Text="{Binding Path=TestString, UpdateSourceTrigger=PropertyChanged}" />
<Button Width="100" Height="30" VerticalAlignment="Top" Content="Click" Click="Button_Click" />
</Grid>
</Window>
Code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var testData = this.DataContext as TestViewModel;
testData.TestString = "Yay, it's change!";
if (testData.HasChanges == true)
{
MessageBox.Show("It's Change!");
}
}
}
public class TestViewModel : ModelBase
{
private string _testString = "test";
public string TestString
{
get { return _testString; }
set
{
if (_testString != value)
{
_testString = value;
RaisePropertyChanged("TestString");
}
}
}
}
public abstract class ModelBase : INotifyPropertyChanged
{
protected ModelBase()
{
}
private bool _hasChanges;
public bool HasChanges
{
get
{
return _hasChanges;
}
set
{
if (_hasChanges != value)
{
_hasChanges = value;
RaisePropertyChanged("HasChanges");
}
}
}
protected void RaisePropertyChanged(string propertyName)
{
HasChanges = true;
this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, e);
}
}
}
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"
I am trying to make ListBox which updates its content according to some changing data.
The XAML is as follows
StackPanel Orientation="Vertical">
<ListBox x:Name="listWatch" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid ShowGridLines="True">
<Grid Grid.Column="0" Background="{Binding Path=Color">
<TextBlock Text="{ Binding Path=LTP}" Padding="2 2 2 2"/>
</Grid>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="btn" Click="btn_Click" Content="Button" />
The class i used for form data strucure is as follows
public class WatchRow : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
string _color;
decimal _lTP;
public WatchRow(decimal LTP,string color)
{
this.LTP = LTP;
this.Color = color;
}
public string Color
{
get { return _color; }
set{
_color = value;
OnPropertyChanged(_color);
}
}
public decimal LTP
{
get { return _lTP; }
set
{
_lTP = value;
OnPropertyChanged(_lTP.ToString());
}
}
protected void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
}
public class Watch:ObservableCollection<WatchRow>
{
public Watch():base()
{
}
}
And the code behind file is like
Watch watch = new Watch();
private void PhoneApplicationPage_Loaded_1(object sender, RoutedEventArgs e)
{
watch.Add(new WatchRow(132, "black"));
watch.Add(new WatchRow(123, "red"));
listWatch.ItemsSource = watch;
watch[0].Color = "green";
}
private void btn_Click(object sender, RoutedEventArgs e)
{
watch[0].Color = "green";
}
My problem is that i am not able to change the color of the list box item by setting the color property(watch[0].Color = "green";) in btn_Click as shown in the code. But the same code works in PhoneApplicationPage_Loaded_1. I don't know what i'm wrong. Any Ideas?
I believe the problem is a slight change to how you are using PropertyChanged. When you are calling OnPropertyChanged, pass through the name of the property that you are changing, rather than the value. For example:
public string Color
{
get { return _color; }
set{
_color = value;
OnPropertyChanged(_color);
}
}
Should be:
public string Color
{
get { return _color; }
set{
_color = value;
OnPropertyChanged("Color");
}
}
Also, I'm not sure if this is necessarily a problem, but this is how I've always created the OnPropertyChanged function:
Instead of:
protected void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
Try:
private void OnPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
Also, as Magnus Johansson mentioned, define a brush, and bind the Color, rather than a string. So the Color property would be (see his explanation for further details on this):
private Color _color;
public Color Color
{
get { return _color; }
set{
_color = value;
OnPropertyChanged("Color");
}
}
Using Mvvm you can resolve your problem:
I've tested this code and it works. You need to split the code in three separate files, like this:
the viewModel
public class WatchViewModel
{
public ObservableCollection<WatchRow> WatchRows { get; set; }
public void GetWatchRows()
{
WatchRows= new ObservableCollection<WatchRow>();
}
public void AddWatchRow(int value, string color)
{
var item=new WatchRow(value, color);
WatchRows.Add(item);
}
}
The model
public class WatchRow : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
string _color;
decimal _lTP;
public WatchRow(decimal LTP, string color)
{
this.LTP = LTP;
this.Color = color;
}
public string Color
{
get { return _color; }
set
{
_color = value;
OnPropertyChanged(_color);
}
}
public decimal LTP
{
get { return _lTP; }
set
{
_lTP = value;
OnPropertyChanged(_lTP.ToString());
}
}
protected void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
}
And the view (code behind of your xaml page)
public partial class MainPage : PhoneApplicationPage
{
private WatchViewModel watch;
public MainPage()
{
InitializeComponent();
watch = new WatchViewModel();
watch.GetWatchRows();
watch.AddWatchRow(132, "green");
watch.AddWatchRow(123, "red");
base.DataContext = watch;
listWatch.ItemsSource = watch.WatchRows;
}
private void btn_Click(object sender, RoutedEventArgs e)
{
watch.AddWatchRow(132, "pink");
watch.AddWatchRow(113, "yellow");
}
}