I have a GridControl(Devexpress v13) in view(WPF). A Datatable set values in ViewModel and assigned to ItemsSource. But ItemsSource filled only initialize. Later Datatable's value changes but it doesn't refresh.
How to ItemsSource refresh?
<dxg:GridControl Name="GridControlData" DataSource="{Binding DtCriterias, Mode=TwoWay}" HorizontalAlignment="Left" VerticalAlignment="Top" AutoGenerateColumns="AddNew" Width="400" Height="100">
I hope you know what I mean.
Any help will be much appreciated.
Thanks in advance.
Edit:
Property changed using:
public DataTable DtCriterias {
get { return _dtCriterias; }
set
{
_dtCriterias = value;
Notify(() => DtCriterias);
}
}
protected void Notify(Expression<Func<object>> expression)
{
if (_propertyChangedEvent == null) return;
Notify(GetPropertyName(expression));
}
protected void Notify(string propertyName)
{
if (_propertyChangedEvent != null)
{
_propertyChangedEvent(this, new PropertyChangedEventArgs(propertyName));
}
}
public ObservableCollection<ClientB2B> Clients
{
get
{
return _clients;
}
set
{
if (_clients == value) return;
_clients = value;
OnPropertyChanged(); // This is what you need
}
}
Implement this interface - INotifyPropertyChanged
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, e);
}
protected void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
I found reason of problem.
I am using encapsulation and I was set private value(_dtCriterias). Therefore Property Changed Event wasn't work.
Definitions:
private DataTable _dtCriterias;
public DataTable DtCriterias {
get { return _dtCriterias; }
set
{
_dtCriterias = value;
Notify(() => DtCriterias);
}
}
When I have problem datatable set:
_dtCriterias = GetValue().DefaultView.ToTable("FooTable");
Solution:
DtCriterias = GetValue().DefaultView.ToTable("FooTable");
Related
I'm trying to validate a property object with FluentValidation when that object changes.
private Empresa empresa { get; set; }
public Empresa Empresa{
get { return empresa; }
set {
if (empresa == value) return;
empresa = value;
RaisePropertyChanged("Empresa");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string empresa)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Empresa"));
}
private void EmpresaViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
CompanyValidator validator = new();
this.ValidationResult = validator.Validate(empresa);
}
But when the property changes in the XAML the set doesn't fire
<TextBox Header="Nome Simplificado"
MinWidth="200"
HorizontalAlignment="Left"
LostFocus="TextBox_LostFocus"
TextChanging="TextBox_TextChanging"
Text="{Binding Empresa.SimplifiedName, Mode=TwoWay,
UpdateSourceTrigger=Default}"
/>
Does anyone know how to get this working?
(Ps. When I instantiate a new object of that class the event fires).
Property Changed not firing UWP
The problem is that Text property binding path is Empresa's property, but not Empresa itself, you just implement RaisePropertyChanged for Empresa instance, So it only works when Empresa is created for the first time.
And if you want to update Text, you need also implement for SimplifiedName property.
public class Empresa:INotifyPropertyChanged
{
private string _simplifiedName;
public string SimplifiedName
{
get { return _simplifiedName; }
set
{
if (_simplifiedName != value)
{
_simplifiedName = value;
RaisePropertyChanged("SimplifiedName");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Update Text
private void MyButton_Click(object sender, RoutedEventArgs e)
{
Empresa.SimplifiedName = "New Value";
}
I am implementing a cart in Xamarin.Forms. In my cart page there is a ListView with data. Each of the cell contains a button to select the count of item and amount. In the cart view there is a grand total label.
My problem is the grand total is not updating while the number picker changes. The calculation method is called upon item adding view cell. I know that i need to implement INotifyProperty for this, but I'm unsure of how to do it.
I have a base view model which inherits INotifyProperty that contains an event.
public class BaseViewModel : INotifyPropertyChanged
{
private double _price;
public double Price
{
get
{
return _price;
}
set
{
_price = value;
OnPropertyChanged("Price");}
}
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
View model
public BaseViewModel()
{
App.Instance.ViewModel = this;
TempList = TempList ?? new ObservableCollection<cm_items>();
this.Title = AppResources.AppResource.Cart_menu_title;
this.Price = CartCell.price;
}
As a design methodology, its better to implement MVVM as a subclass and implement it to your ViewModel.
Sample Implementation:
public class ObservableProperty : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
I also strongly suggest implementing ICommand as a Dictionary structure like:
public abstract class ViewModelBase : ObservableProperty
{
public Dictionary<string,ICommand> Commands { get; protected set; }
public ViewModelBase()
{
Commands = new Dictionary<string,ICommand>();
}
}
So all todo in your ViewModel is just inherit the ViewModelBase class and use it
class LoginViewModel : ViewModelBase
{
#region fields
string userName;
string password;
#endregion
#region properties
public string UserName
{
get {return userName;}
set
{
userName = value;
OnPropertyChanged("UserName");
}
}
public string Password
{
get{return password;}
set
{
password = value;
OnPropertyChanged("Password");
}
}
#endregion
#region ctor
public LoginViewModel()
{
//Add Commands
Commands.Add("Login", new Command(CmdLogin));
}
#endregion
#region UI methods
private void CmdLogin()
{
// do your login jobs here
}
#endregion
}
Finally: Xaml Usage:
<Entry Placeholder="Username" Text="{Binding UserName}"/>
<Entry Placeholder="Password" Text="{Binding Password}" IsPassword="True"/>
<Button Text="Login" Command="{Binding Commands[Login]}"/>
For example try this view model:
public abstract class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetPropertyValue<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (value == null ? field != null : !value.Equals(field))
{
field = value;
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
return true;
}
return false;
}
}
and in inherited classes use it like this:
private int myProperty;
public int MyProperty
{
get { return this.myProperty; }
set { this.SetPropertyValue(ref this.myProperty, value); }
}
When I started Xamarin coding, the MVVM was a bit confusing until I discovered that the PropertyChangedEvent on the ViewModel fired off a signal to the View (ContentPage), and updated the Label/textbox/etc.
For those looking for the 'latest and greatest'... Here's some revised code:
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
and on your property Setter:
public string SomeProperty
{
get { return _somProperty; }
set
{
_someProperty= value;
OnPropertyChanged();
}
}
}
Nice? No? Saves having to pass the property name each time!
So I've got the following ComboBox with the SelectedValue bound to the Property below. With the following binding, when I set value, the binding/RaisePropertyChanged combination is throwing a StackOverflow Exception.
Here's the ComboBox
<ComboBox x:Name="WireType" ItemsSource="{x:Bind ViewModel.WireTypes}" SelectedValue="{x:Bind ViewModel.WireType, Mode=TwoWay}"/>
Here's the Property
public string WireType
{
get
{
return _wireType;
}
set
{
_wireType = value;
RaisePropertyChanged();
}
}
And here's the RaisePropertyChanged method.
private void RaisePropertyChanged([CallerMemberName] string caller = "")
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(caller));
}
}
I'm pretty sure I've done this before. What am I missing?
My psychic powers suggest that the PropertyChanged event is trying to set the property value.
The setter should protect against the case where the value didn't change. ie-
set
{
if (_wireType != value) // or the appropriate comparison for your specific case
{
_wireType = value;
RaisePropertyChanged();
}
}
Of course a stack trace would confirm what's actually happening.
Try this
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string caller = "")
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(caller));
}
there is probably a really simple reason why this isnt working but I've tried everything. I have a TextBlock with Text bound to a variable, the variable changes but the Text doesn't :
<TextBlock x:Name="modeLabel" Style="{StaticResource IndiTextBlock}" Height="23" TextWrapping="Wrap" Grid.Row="0" Text="{Binding ModeLabelText}" Margin="35,22,58,0"/>
The code that controls the text value is in a viewmodel:
public string ModeLabelText { get { return _modeLabeltext; } }
public ComboBoxItem SelectedMode { get { return _selectedMode; }
set
{
if (_selectedMode == value) return;
_selectedMode = value;
ToggleMode(null);
EvaluateScenario(null);
}
and
private void ToggleMode(object parameter)
{
if (_isBasicCalculation)
{
_modeLabeltext = "Target profit";
_isBasicCalculation = false;
}
else
{
_modeLabeltext = "Total to invest";
_isBasicCalculation = true;
}
}
Your class has to implement the INotifyPropertyChanged interface, and on changes of your variables, you should trigger the event
public class Model : INotifyPropertyChanged
{
public event EventHandler PropertyChanged; // event from INotifyPropertyChanged
protected void RaisePropertyChanged(string propertyName)
{
var local = PropertyChanged;
if (local != null)
{
local.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public void ToggleMode()
{
// ... your code ...
RaisePropertyChanged("ModelLabelText");
}
}
Thank you Nguyen Kien
private void ToggleMode(object parameter)
{
if (_isBasicCalculation)
{
_modeLabeltext = "Target profit";
OnPropertyChanged("ModeLabelText");
_isBasicCalculation = false;
}
else
{
_modeLabeltext = "Total to invest";
OnPropertyChanged("ModeLabelText");
_isBasicCalculation = true;
}
}
I have a listbox which has items populated from a database. Now I want to update a listbox with a new string value each time I call the Add function.
I did this in 2 ways.
I added the new value to the database and updated the ViewModel class where the listbox is binded to. And this works fine. (see AddNewNameFirstWay method below)
I added the new value to the database, reloaded the values from the database and updated the ViewModel. But this doesn't work. (see AddNewNameSecondWay method below)
Here is my ViewModel code
public class ViewModel
{
private DBContext context = new DBContext("Data source=isostore:/names2.sdf");
private ObservableCollection<NameTable> nameCollection;
public ObservableCollection<NameTable> NameCollection
{
get
{
return nameCollection;
}
set
{
if (nameCollection != value)
{
nameCollection = value;
NotifyPropertyChanged();
}
}
}
public void AddNewNameSecondWay(string s)
{
NameTable t = new NameTable() { Name = s };
context.NameDatabaseTable.InsertOnSubmit(t);
context.SubmitChanges();
LoadFromDB();
}
public void AddNewNameFirstWay(string s)
{
NameTable t = new NameTable() { Name = s };
context.NameDatabaseTable.InsertOnSubmit(t);
context.SubmitChanges();
NameCollection.Add(t);
}
public void LoadFromDB()
{
var query = from i in context.NameDatabaseTable
select i;
NameCollection = new ObservableCollection<NameTable>(query);
}
private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName]string propertyName = null)
{
var tmp = PropertyChanged;
if (tmp != null)
tmp(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Here is my XAML binding code
<ListBox ItemsSource="{Binding NameCollection, Mode=OneWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name, Mode=OneWay}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
It seems to me that second method doesn't work, because the ObservableCollection memory reference changes. If this is correct, how to update the binding properly?
Reason I use the second method is that, I want to make sure all the DB constraints stands true for the values I insert.
You need to notify about the changes in property. Try this way for Framework 4.0,
Mode=OneWayToSource,UpdateSourceTrigger=PropertyChanged
Hope it helps...
Call OnPropertyChanged when you want notification about changes in your collection:
OnPropertyChanged("NameCollection")
Your ViewModel:
public class ViewModel: INotifyPropertyChanged
{
private DBContext context = new DBContext("Data source=isostore:/names2.sdf");
private ObservableCollection<NameTable> nameCollection;
public ObservableCollection<NameTable> NameCollection
{
get
{
return nameCollection;
}
set
{
if (nameCollection != value)
{
nameCollection = value;
OnPropertyChanged("NameCollection");
}
}
}
public void AddNewNameSecondWay(string s)
{
// your code
OnPropertyChanged("NameCollection");
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}