I am using INotifyPropertyChanged but it will give me null when I shaw the PropertyChanged so what i can do..
my code is like this..
public class Entities : INotifyPropertyChanged
{
public Entities(int iCount)
{
_iCounter = iCount;
}
private int _iCounter;
public int iCounter
{
get
{
return _iCounter;
}
set
{
value = _iCounter;
NotifyPropertyChanged("iCounter");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
Thanks...
I tried putting your code in my program and it is working fine. I am getting the EventArg as the property:
class Program
{
static void Main(string[] args)
{
var ent = new Entities(10);
ent.PropertyChanged += new PropertyChangedEventHandler(ent_PropertyChanged);
ent.iCounter = 100;
}
static void ent_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
throw new NotImplementedException();
}
}
public class Entities : INotifyPropertyChanged
{
public Entities(int iCount)
{
_iCounter = iCount;
}
private int _iCounter;
public int iCounter
{
get
{
return _iCounter;
}
set
{
_iCounter = value;
NotifyPropertyChanged("iCounter");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
What is the exact erro you are getting?
This is i think a bug in INotifyPropertyChanged .
There can be 2 workaround
1st Workaround
1- Assign iCounter property to a UI control like Lable.
2- Now change the value of the property this time , PropertyChanged event will have a reference of your method and will not be null;
2nd workaround
Assign PropertyChanged delegate in the Entities class constructor
i am giving the demo code in WPF
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.Resources>
<ToolTip x:Key="#tooltip">
<TextBlock Text="{Binding CompanyName}"/>
</ToolTip>
</Grid.Resources>
<TextBlock Text="{Binding Name}" Background="LightCoral" />
<Rectangle Width="200" Height="200" Fill="LightBlue" VerticalAlignment="Center" HorizontalAlignment="Center" ToolTip="{DynamicResource #tooltip}" Grid.Row="1"/>
<Button Click="Button_Click" Grid.Row="2" Margin="20">Click Me</Button>
</Grid>
see here CompanyName is assigned to a tool tip.
// this is Window1.Cs file
public Window1()
{
DataContext = DemoCustomer.CreateNewCustomer();
InitializeComponent();
}
// Now DemoCustomer Class
public class DemoCustomer : INotifyPropertyChanged
{
// These fields hold the values for the public properties.
private Guid idValue = Guid.NewGuid();
private string customerName = String.Empty;
private string companyNameValue = String.Empty;
private string phoneNumberValue = String.Empty;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
// The constructor is private to enforce the factory pattern.
private DemoCustomer()
{
customerName = "no data";
companyNameValue = "no data";
phoneNumberValue = "no data";
}
// This is the public factory method.
public static DemoCustomer CreateNewCustomer()
{
return new DemoCustomer();
}
// This property represents an ID, suitable
// for use as a primary key in a database.
public Guid ID
{
get
{
return this.idValue;
}
}
public string CompanyName
{
get { return this.companyNameValue; }
set
{
if (value != this.companyNameValue)
{
this.companyNameValue = value;
OnPropertyChanged("CompanyName");
}
}
}
public string PhoneNumber
{
get { return this.phoneNumberValue; }
set
{
if (value != this.phoneNumberValue)
{
this.phoneNumberValue = value;
OnPropertyChanged("PhoneNumber");
}
}
}
}
and finally changing the value
private void Button_Click(object sender, RoutedEventArgs e)
{
DemoCustomer dc = this.DataContext as DemoCustomer;
dc.CompanyName = "Temp";
}
Related
Help me please!!!
I have 3 UserControls
I select user on List Users UC listbox
Then send message from SendMessage UC to Database
when i send message to Db it must refresh my chat listBox in Correspondence UC, but problem is in my ChatWrapper.
PropertyChanged in ChatWrapper is always null, and I can't refresh my ListBox in Correspondence UC with new message
List Users:
public IEnumerable<EmployeesDb> getListNames
{
get { return Db.Instance.EmployeesDbs.ToList(); }
}
static EmployeesDb m_selectedUser;
public static EmployeesDb selectedUser
{
get { return m_selectedUser; }
set
{
if (value != null)
m_selectedUser = value;
Correspondence correspondence = new Correspondence();
correspondence.CorrespondenceChat();
}
}
}
Send Message ( I try to refresh -> SendInfo.FirstOrDefault().RefreshGUI();)
public static DependencyProperty SendInfoProperty =
DependencyProperty.Register(
"SendInfo",
typeof(IEnumerable<ChatWrapper>),
typeof(SendMessage));
public IEnumerable<ChatWrapper> SendInfo
{
get { return GetValue(SendInfoProperty) as IEnumerable<ChatWrapper>; }
set { SetValue(SendInfoProperty, value); }
}
void SendMessageCommandExecute()
{
//...
SendInfo.FirstOrDefault().RefreshGUI();
//...
}
ChatWrapper
public class ChatWrapper : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void FirePropertyChanged(string name)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(name));
}
public void RefreshGUI()
{
FirePropertyChanged("message");
}
public ChatDb chatDb { get; set; }
public string message
{
get
{
return (chatDb != null) ? string.Format("{0} {1}.{2} / {3} / {4}\n{5}",
chatDb.FromEmployeesDb.surname,
chatDb.FromEmployeesDb.name[0],
chatDb.FromEmployeesDb.middleName[0],
chatDb.messageDateTime,
chatDb.computerName,
chatDb.message) : null;
}
}
Correspondence
//...
public partial class Correspondence : UserControl, INotifyPropertyChanged
{
public static DependencyProperty GetCorrespondenceInfoProperty =
DependencyProperty.Register(
"GetCorrespondenceInfo",
typeof(IEnumerable<ChatWrapper>),
typeof(Correspondence),
new PropertyMetadata(OnChanged));
public IEnumerable<ChatWrapper> GetCorrespondenceInfo
{
get { return GetValue(GetCorrespondenceInfoProperty) as IEnumerable<ChatWrapper>; }
set { SetValue(GetCorrespondenceInfoProperty, value); }
}
static void OnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var me = d as Correspondence;
me.chat = me.GetCorrespondenceInfo;
}
ICollectionView m_CollectionView;
public static IEnumerable<ChatWrapper> m_chat;
public IEnumerable<ChatWrapper> chat
{
get { return m_chat; }
set
{
m_chat = value;
if (ListUsers.selectedUser != null)
CorrespondenceChat();
FirePropertyChanged("chat");
}
}
public void CorrespondenceChat()
{
if (m_chat == null)
return;
m_CollectionView = CollectionViewSource.GetDefaultView(m_chat);
//...
FirePropertyChanged("chat");
}
XAML of Correspondence (refresh
<Grid>
<ListBox x:Name="correspondenceListBox" ItemsSource="{Binding chat, RelativeSource={RelativeSource AncestorType={x:Type local:Correspondence}}}"
Height="auto" Grid.Row="0" Grid.Column="1" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding message}" TextWrapping="Wrap" Width="auto"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
I tried to write
public event PropertyChangedEventHandler PropertyChanged = delegate { };
PropertyChanged is no longer null, but it's still not updated
I searched through all other question with the same problem. But I can't find any solution from them.
OnPropertyChanged is firing but the Control is not updating. I'm using the Mahapps.Metro ProgressRing Control.
View Code
<controls:MetroWindow.Resources>
<userObj:LoginViewLogic x:Key="UserData"/>
<userObj:LoginViewLogic x:Key="LoginViewLogic"/>
</controls:MetroWindow.Resources>
<Grid>
<Canvas>
<controls:ProgressRing Name="ProgressRing" Canvas.Left="133" Canvas.Top="154" Height="50" Width="35" IsActive="{Binding Source={StaticResource UserData},Path=UserData.IsProgressRingActive}"/>
</Canvas>
</Grid>
ViewModel Code
public class LoginViewLogic {
public LoginViewLogic() {
_userData = new User(AppSettings.ReadCredentials(),(bool)loadedSettings);
}
private User _userData;
public User UserData
{
get { return _userData; }
set { _userData = value; }
}
public async void Login() {
_userData.IsProgressRingActive = true;
var loginResult = await Stuff.Login(_userData);
if (!loginResult) {
MessageBox.Show("You have entered an invalid username or password",
"Information", MessageBoxButton.OK, MessageBoxImage.Error);
_userData.IsProgressRingActive = false;
}
}
Model Code
public class User : INotifyPropertyChanged {
private bool _isProgressRingActive;
public bool IsProgressRingActive {
get { return _isProgressRingActive; }
set {
_isProgressRingActive = value;
OnPropertyChanged("IsProgressRingActive");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Have you tried this:
<controls:MetroWindow.Resources>
<userObj:LoginViewLogic x:Key="LoginViewLogic"/>
</controls:MetroWindow.Resources>
<Grid>
<Canvas>
<controls:ProgressRing Name="ProgressRing" Canvas.Left="133" Canvas.Top="154" Height="50" Width="35" IsActive="{Binding Source={StaticResource LoginViewLogic},Path=UserData.IsProgressRingActive}"/>
</Canvas>
</Grid>
So you are only creating and binding to one instance of LoginViewLogic class?
Your viewmodel should also raise a PropertyChanged event.
Try with below code.
public class LoginViewLogic : INotifyPropertyChanged
{
public LoginViewLogic()
{
_userData = new User(AppSettings.ReadCredentials(),(bool)loadedSettings);
}
private User _userData;
public User UserData
{
get { return _userData; }
set { _userData = value; }
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
I have a Listbox where it's items are objects. In these objects I store two colors.
I want to bind these colors with an other object's property, but how can I achieve this?
The listbox looks like this:
Listbox1.Items.Add(new ColorAndMoreClass(Color.Red, Color.Blue));
Far away, in an other class there is a property which I'd like to bind to.
How can I do that?
Your rootclass could look like this.
In the class you have a object representing a different Class.
public class ColorAndMoreClass: INotifyPropertyChanged
{
private Color _c;
private Color _c2;
private OtherClass _example;
public ColorAndMoreClass(Color c, Color c2)
{
_c= c;
_c2 = c2;
}
public OtherClass example
{
get { return _example }
set
{
_example = value;
OnPropertyChanged("example");
}
}
public Color c
{
get { return _c; }
set
{
_c= value;
OnPropertyChanged("c");
}
}
public Color c2
{
get { return _c2; }
set
{
_c2 = value;
OnPropertyChanged("c2");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
}
Your other class could look like this. I just took a simple string.
public class OtherClass : INotifyPropertyChanged
{
private String _someOtherProperty;
public OtherClass(){}
public String someOtherProperty
{
get { return _someOtherProperty; }
set
{
_someOtherProperty= value;
OnPropertyChanged("someOtherProperty");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
}
In your Code behind make a property the Listbox can bind to
public List<ColorAndMoreClass>> ListOfColorAndMore{ get; set; }
public Window1()
{
ListOfColorAndMore = GetDataThatFillsUpTheProperty();
InitializeComponent();
DataContext = this;
}
Your XAML could then look like this. The Datatemplate is used to tell XAML how to display your object.
<Grid>
<ListBox ItemsSource={Binding ListOfColorAndMore}>
<DataTemplate x:Key="myTaskTemplate">
<StackPanel>
<TextBlock Text="{Binding Path=c.R}" />
<TextBlock Text="{Binding Path=c2.R}"/>
<TextBlock Text="{Binding Path=example.someOtherProperty}"/>
</StackPanel>
</DataTemplate>
</ListBox>
</Grid>
I hope it is this that you mean. But your question is not that clear.
I'm trying to create a WP8 app which gets data from a website and displays them.
I chose the panorama template and Visual Studio created some default code.
What I am trying to do is, that the textblock automatically gets updated if I change the variable the text is bound to. But calling changeDate() doesn't change the UI. The textbox still says "dd.mm.yyyy".
MainPage.xaml:
<phone:LongListSelector.ListHeaderTemplate>
<DataTemplate>
<Grid Margin="12,0,0,38">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock
Text="{Binding Date}"
Style="{StaticResource PanoramaItemHeaderTextStyle}"
Grid.Row="0">
<TextBlock.DataContext>
<ViewModels:MainViewModel/>
</TextBlock.DataContext>
</TextBlock>
</Grid>
</DataTemplate>
</phone:LongListSelector.ListHeaderTemplate>
.
MainViewModel.cs:
public class MainViewModel : INotifyPropertyChanged
{
[...]
private string _date = "dd.mm.yyyy";
public string Date
{
get
{
return _date;
}
set
{
if (value != _date)
{
_date = value;
NotifyPropertyChanged("Date");
}
}
}
//public void changeDate()
//{
// Date = "fu";
// App.ViewModel.Date = "bar";
//}
**UPDATE 2**
public bool IsDataLoaded
{
get;
private set;
}
public void LoadData()
{
System.Net.WebClient wc = new System.Net.WebClient();
wc.DownloadStringCompleted += wc_DownloadStringCompleted;
wc.DownloadStringAsync(new Uri("somelink"));
}
private void wc_DownloadStringCompleted(object sender, System.Net.DownloadStringCompletedEventArgs e)
{
string s = FilterData(e.Result);
}
private string FilterData(string s)
{
string[] split = System.Text.RegularExpressions.Regex.Split(s, "<tbody>");
s = split[1];
split = System.Text.RegularExpressions.Regex.Split(s, "</tbody>");
s = split[0];
split = System.Text.RegularExpressions.Regex.Split(s, "\r\n");
foreach(string str in split)
{
if (str.Contains("class=\"xl24\""))
{
App.ViewModel.Date = "somedate";
}
}
return s;
}
**END UPDATE 2**
[...]
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
UPDATE 1
MainPage.xaml.cs:
public MainPage()
{
InitializeComponent();
DataContext = App.ViewModel;
}
**UPDATE 2**
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
}
}
**END UPDATE 2**
[...]
.
App.xaml.cs:
private static MainViewModel viewModel = null;
public static MainViewModel ViewModel
{
get
{
if (viewModel == null)
viewModel = new MainViewModel();
return viewModel;
}
}
[...]
What I think is happening is that your NotifyPropertyChanged is called from some worker thread which could result in calling Date getter from the same worker thread. If an UI element calls data getter from worker thread (instead from Main UI thread) operation ends with "Invalid cross-thread access". If that's so, you should make handler call from Main thread. For example:
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
Dispatcher dsp = Deployment.Current.Dispatcher;
dsp.BeginInvoke(() => {
handler(this, new PropertyChangedEventArgs(propertyName));
});
}
}
Hope it helps
<TextBlock.DataContext>
<ViewModels:MainViewModel/>
</TextBlock.DataContext>
This creates a new MainViewModel object and you are not updating this object but the one you stored in the App object.
To solve this: set the data context of the View to the App.ViewModel object (no need to set the data context of the TextBlock)
Extra: Please do NOT use this code:
public void changeDate()
{
Date = "fu";
App.ViewModel.Date = "bar";
}
Now your ViewModel knows about the App. Just use:
public void changeDate()
{
Date = "fu";
}
I've checked the existing answers on Stack and still can't get this correct:
In my View:
<TextBlock Margin="8,0,0,0"
FontSize="48"
Text="{Binding YearsToSave}"
d:LayoutOverrides="Width">
...
<SurfaceControls:SurfaceSlider x:Name="slider" Grid.Row="8"
Grid.Column="2"
VerticalAlignment="Bottom"
Maximum="{Binding YearsToSaveMaxValue}"
Minimum="{Binding YearsToSaveMinValue}"
Value="{Binding YearsToSave}"
d:LayoutOverrides="Width" />
In my view model:
class YearsToSaveViewModel : INotifyPropertyChanged
{
private int yearsToSave;
public event PropertyChangedEventHandler PropertyChanged;
public YearsToSaveViewModel()
{
Questions = new SavingsCalculatorQuestions();
YearsToSave = 5; //Binds correctly
YearsToSaveMinValue = 0;
YearsToSaveMaxValue = 30;
}
public SavingsCalculatorQuestions Questions { get; set; }
public int YearsToSaveMinValue { get; private set; }
public int YearsToSaveMaxValue { get; private set; }
public int YearsToSave
{
get { return yearsToSave; }
set
{
yearsToSave = value;
OnPropertyChanged("YearsToSave");
}
}
public void Reset()
{
YearsToSave = 0;
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
switch (name)
{
case "YearsToSave":
Questions.NumberOfYears = YearsToSave;
break;
}
}
}
}
The property changed event fires correctly and gets the value, updates the Questions.NumberOfYears correctly but the change never propagates back to the view.
Your OnPropertyChanged method is not raising the PropertyChanged event...
Update your method like so:
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
switch (name)
{
case "YearsToSave":
Questions.NumberOfYears = YearsToSave;
handler(this, new PropertyChangedEventArgs(name));
break;
}
}
}
Another option is using the NotifyPropertyWeaver Project!
I like it,because it automatically does the Event call for you!
(a bit of black magic but convenient)
See
http://crosscuttingconcerns.com/NotifyPropertyWeaver