Implementing INotifyPropertyChanged using LINQ-to-SQL - c#

I'm builing a Windows Phone 8 app using LINQ-to-SQL for my entities. My current implementation uses the simple INotifyPropertyChanging/INotififyPropertyChanged methods:
[Table]
public class Item : INotifyPropertyChanged, INotifyPropertyChanging
{
private int _itemId;
[Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", AutoSync = AutoSync.OnInsert)]
public int ItemId
{
get { return _itemId; }
set
{
if (_itemId != value)
{
NotifyPropertyChanging("ItemId");
_itemId = value;
NotifyPropertyChanged("ItemId");
}
}
}
[Column]
internal int? _groupId;
private EntityRef<Board> _group;
[Association(Storage = "_group", ThisKey = "_groupId", OtherKey = "GroupId", IsForeignKey = true)]
public Group Group
{
get { return _group.Entity; }
set
{
NotifyPropertyChanging("Group");
_group.Entity = value;
if (value != null)
{
_groupId = value.BoardId;
}
NotifyPropertyChanging("Group");
}
}
}
I want to change the property setter to my new method, I've founded here: http://danrigby.com/2012/04/01/inotifypropertychanged-the-net-4-5-way-revisited/
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (object.Equals(storage, value)) return false;
this.OnPropertyChanging(propertyName);
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
It's easy to implement for a property like ItemId, but I don't know how to implement it for GroupId because the value should be set on _group.Entity and this can not be passed as reference.
This is my workaround (not tested yet), but I think the PropertyChanging/PropertyChanged events will be raised to early:
public Group Group
{
get { return _group.Entity; }
set
{
var group = _group.Entity;
if (SetProperty(ref group, value))
{
_group.Entity = group;
if (value != null)
{
_groupId = value.GroupId;
}
}
}
}
Is there clear solution for this issue?

I have found a solution. Just overload the method with another implementation:
protected T SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
{
return value;
}
NotifyPropertyChanging(propertyName);
field = value;
NotifyPropertyChanged(propertyName);
return value;
}
protected T SetProperty<T>(ref EntityRef<T> field, T value, [CallerMemberName] string propertyName = null) where T : class
{
NotifyPropertyChanging(propertyName);
field.Entity = value;
NotifyPropertyChanged(propertyName);
return value;
}
Call it like this:
public Group Group
{
get { return _board.Entity; }
set
{
if (SetProperty(ref _group, value) != null)
{
_groupId = value.GroupId;
}
}
}

Related

RaisePropertyChanged in a nested ObservableCollection not updating

I am right now using a nested ObservableCollection to fill in the rows of a DataGrid with the inner ObservableCollection holding information regarding each cell as follows:
public class MemoryTable : INotifyPropertyChanged
{
string _Address;
public string Address
{
get
{
return _Address;
}
set
{
if (_Address != value)
{
_Address = value;
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
}
bool _NextRowOverflow;
public bool NextRowOverflow
{
get
{
return _NextRowOverflow;
}
set
{
if (_NextRowOverflow != value)
{
_NextRowOverflow = value;
}
}
}
private ObservableCollection<DataAssets> _DataSpace;
public ObservableCollection<DataAssets> DataSpace
{
get
{
return _DataSpace;
}
set
{
_DataSpace = value;
RaisePropertyChanged("DataSpace");
}
}
public MemoryTable()
{
DataSpace = new ObservableCollection<DataAssets>();
}
public class DataAssets : INotifyPropertyChanged
{
string _Addresses;
public string Addresses
{
get
{
return _Addresses;
}
set
{
if (_Addresses != value)
{
_Addresses = value;
RaisePropertyChanged("Addresses");
}
}
}
string _Values;
public string Values
{
get
{
return _Values;
}
set
{
if (_Values != value)
{
_Values = value;
RaisePropertyChanged("Values");
}
}
}
string _ToolTip;
public string ToolTip
{
get
{
return _ToolTip;
}
set
{
if (_ToolTip != value)
{
_ToolTip = value;
RaisePropertyChanged("ToolTip");
}
}
}
Brush _Color;
public Brush Color
{
get
{
return _Color;
}
set
{
if (_Color != value)
{
_Color = value;
RaisePropertyChanged("Color");
}
}
}
string _ConvertedValue;
public string ConvertedValue
{
get
{
return _ConvertedValue;
}
set
{
if (_ConvertedValue != value)
{
_ConvertedValue = value;
RaisePropertyChanged("ConvertedValue");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
}
}
}
}
And want it to update whenever I change one of the values in the DataAsset class, however whenever I change a value by such a means:
NextRow.DataSpace[i].Color = Brushes.Yellow;
None of the cells update, the workaround i made for doing this is to clear and rewrite the entire ObservableCollection like this:
ObservableCollection<MemoryTable> Temp = new ObservableCollection<MemoryTable>();
foreach (var item in MemoryTable)
{
if (Temp.IndexOf(item) < 0)
{
Temp.Add(item);
}
}
MemoryTableDisplay.Clear();
foreach (var item in Temp)
{
if (MemoryTableDisplay.IndexOf(item) < 0)
{
MemoryTableDisplay.Add(item);
}
}
By this method I am able to force the UI to display the changes, however when moving further to working on a larger set of data, this method takes too long to accomplish, is it possible to have the inner properties to cause an update for the entire ObservableCollection?
Thank you!
Please try this.
NextRow.DataSpace[i].Color = Brushes.Yellow;
After writing down one more statement like this.
NextRow.DataSpace= NextRow.DataSpace;

Why my ICollection is always empty?

I am trying to reach a foreach but my program never gets inside because my ICollection Coletores is always empty even if I put a lot of stuff in there.
The code where I want to get inside and it is always empty (I want to get inside the second foreach):
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
if (NavigationContext.QueryString.TryGetValue("email", out email))
{
//MessageBox.Show(email);
List<HyperlinkButton> listaLinks = new List<HyperlinkButton>();
AppDataContext db = new AppDataContext();
int i = 0;
HyperlinkButton aux = new HyperlinkButton();
foreach (Pessoa pessoa in db.Pessoas)
{
if (pessoa.Email == email)
{
foreach (Coletor coletor in pessoa.Coletores)
{
aux.Content = "Coletor " + (i + 1).ToString();
aux.FontSize = 24;
aux.NavigateUri = new Uri("/OcorrenciasPage.xaml?coletorId=" + coletor.Id.ToString(), UriKind.RelativeOrAbsolute);
listaLinks.Add(aux);
i++;
}
}
}
ListBox coletores = new ListBox();
coletores.ItemsSource = listaLinks;
stcList.Children.Add(coletores);
}
base.OnNavigatedTo(e);
}
Now the code that I am adding data:
if (txtLat.Text != "" && txtLong.Text != "" && rdNorte.IsChecked == true || rdSul.IsChecked == true && rdLeste.IsChecked == true || rdOeste.IsChecked == true)
{
foreach (var pessoa in db.Pessoas)
{
if (pessoa.Email == email)
{
pessoa.Coletores.Add(coletor);
}
}
db.Coletores.InsertOnSubmit(coletor);
db.SubmitChanges();
NavigationService.Navigate(new Uri("/ColetoresPage.xaml?email=" + email, UriKind.RelativeOrAbsolute));
}
Now, my Pessoa class:
public class Pessoa : INotifyPropertyChanged
{
private int _id;
[Column(IsDbGenerated = true, IsPrimaryKey = true)]
public int Id {
get { return _id;}
set { _id = value;
OnPropertyChanged("Id");
}
}
private string _nome;
[Column]
public string Nome
{
get { return _nome; }
set { _nome = value;
OnPropertyChanged("Nome");
}
}
private string _email;
[Column]
public string Email
{
get { return _email; }
set { _email = value;
OnPropertyChanged("Email");
}
}
private string _senha;
[Column]
public string Senha { get { return _senha; }
set { _senha = value;
OnPropertyChanged("Senha");
}
}
private string _profissao;
[Column]
public string Profissao { get { return _profissao; }
set { _profissao = value;
OnPropertyChanged("Profissao");
}
}
private int _idade;
[Column]
public int Idade { get { return _idade; }
set { _idade = value;
OnPropertyChanged("Idade");
}
}
private string _endereco;
[Column]
public string Endereco { get { return _endereco; }
set { _endereco = value;
OnPropertyChanged("Endereco");
}
}
private string _cidade;
[Column]
public string Cidade { get { return _cidade; }
set { _cidade = value;
OnPropertyChanged("Cidade");
}
}
private string _estado;
[Column]
public string Estado { get { return _estado; }
set { _estado = value;
OnPropertyChanged("Estado");
}
}
private EntitySet<Coletor> _coletores = new EntitySet<Coletor>();
[Association(Name = "FK_Coletores_PessoaColetores", Storage = "_coletores", ThisKey = "Id", OtherKey = "pessoaId")]
public ICollection<Coletor> Coletores
{
get { return _coletores; }
set { _coletores.Assign(value); }
}
private EntitySet<PessoaColetor> _pessoaColetores = new EntitySet<PessoaColetor>();
[Association(Name = "FK_PessoaColetores_Pessoas", Storage = "_pessoaColetores", OtherKey = "pessoaId", ThisKey = "Id")]
private ICollection<PessoaColetor> PessoaColetores
{
get { return _pessoaColetores; }
set { _pessoaColetores.Assign(value); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
The Coletores property on the Pessoa class looks alright. There is also a PessoaColetores property. Are you sure there has been no confusion between the two? Especially with intellisense one might dot or tab the wrong one.
Have you put a break point on the line that actually adds coletors (second code snippet)? Maybe stuff is added to the wrong collection.
Cheers, B.

wp8 local database issue

I have created local database in windows phone 8 app. I have 4 fields.
userID - int
Username - string
FileName - string
FileByte - byte[]
What I am doing is trying to update the FileByte column. But when I update the column I get exception SQL Server does not handle comparison of NText, Text, Xml, or Image data types.
Here is my DataTable
[Table]
public class UserFilesDetailsTable : INotifyPropertyChanged, INotifyPropertyChanging
{
// Define ID: private field, public property, and database column.
private int _userID;
[Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int userID
{
get { return _userID; }
set
{
if (_userID != value)
{
NotifyPropertyChanging("userID");
_userID = value;
NotifyPropertyChanged("userID");
}
}
}
// Define item name: private field, public property, and database column.
private string _Username;
[Column(DbType = "NVarChar(100) NOT NULL", CanBeNull = false)]
public string Username
{
get { return _Username; }
set
{
if (_Username != value)
{
NotifyPropertyChanging("Username");
_Username = value;
NotifyPropertyChanged("Username");
}
}
}
// Define item name: private field, public property, and database column.
private string _Filename;
[Column(DbType = "NVarChar(100) NOT NULL", CanBeNull = false)]
public string Filename
{
get { return _Filename; }
set
{
if (_Filename != value)
{
NotifyPropertyChanging("Filename");
_Filename = value;
NotifyPropertyChanged("Filename");
}
}
}
// Define item name: private field, public property, and database column.
private byte[] _Filebytes;
[Column(DbType = "image")]
public byte[] Filebytes
{
get { return _Filebytes; }
set
{
if (_Filebytes != value)
{
NotifyPropertyChanging("Filebytes");
_Filebytes = value;
NotifyPropertyChanged("Filebytes");
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
// Used to notify that a property changed
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region INotifyPropertyChanging Members
public event PropertyChangingEventHandler PropertyChanging;
// Used to notify that a property is about to change
private void NotifyPropertyChanging(string propertyName)
{
if (PropertyChanging != null)
{
PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}
}
#endregion
}
Here my Update query
public void addFiles(int userID, string userName, string fileName, byte[] fileBytes)
{
try
{
if (!(databaseTablesDB.usersFileDetailsTable.Where(f => f.Filename == fileName).Any()))
{
databaseTablesDB.usersFileDetailsTable.InsertOnSubmit(new UserFilesDetailsTable { userID = userID, Username = userName, Filename = fileName, Filebytes = fileBytes });
// Save changes to the database.
databaseTablesDB.SubmitChanges();
}
else
{
var fileDetails = (from file in databaseTablesDB.usersFileDetailsTable where file.Filename == fileName && file.Username == userName select file).FirstOrDefault();
if (fileDetails != null)
{
fileDetails.Filebytes = fileBytes;
}
databaseTablesDB.SubmitChanges();
}
}
catch (Exception ex)
{
}
}
I am not getting where is the issue. Can some one please help to solve this?
Take a look at SQL Server does not handle comparison of NText, Text, Xml, or Image data types. It suggests you change the type of your FileByte column to VARBINARY(MAX).

DuplicateKeyException and SqlCeException SQL Ce WP8

I have problem with windows phone 8 local database. That's how my database code looks:
[Table(Name = "Folders")]
public class FolderTable : INotifyPropertyChanged, INotifyPropertyChanging, IEqualityComparer<FolderTable>
{
private string _folderName;
private string _description;
private string _password;
private string _tileColorName;
[Column(IsPrimaryKey = true)]
public string FolderName
{
get { return _folderName; }
set
{
if (_folderName != value)
{
NotifyPropertyChanging();
_folderName = value;
NotifyPropertyChanged();
}
}
}
[Column(CanBeNull = false)]
public string Description
{
get { return _description; }
set
{
if (_description != value)
{
NotifyPropertyChanging();
_description = value;
NotifyPropertyChanged();
}
}
}
[Column]
public string Password
{
get { return _password; }
set
{
if (_password != value)
{
NotifyPropertyChanging();
_password = value;
NotifyPropertyChanged();
}
}
}
[Column]
public string TileColorName
{
get { return _tileColorName; }
set
{
if (_tileColorName != value)
{
NotifyPropertyChanging();
_tileColorName = value;
NotifyPropertyChanged();
}
}
}
private void NotifyPropertyChanging([CallerMemberName] string propertyName = "")
{
if ( PropertyChanging != null)
PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
if ( PropertyChanged != null )
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangingEventHandler PropertyChanging;
public bool Equals(FolderTable x, FolderTable y)
{
return x.FolderName == y.FolderName;
}
public int GetHashCode(FolderTable obj)
{
return obj.FolderName.GetHashCode();
}
}
Folder add:
public Task Add(Folder folder)
{
var folderTable = GetFolderTable(folder);
_databaseContext.Folders.InsertOnSubmit(folderTable);
return Task.FromResult(true);
}
Commit:
public Task Commit()
{
try
{
_databaseContext.Folders.Context.SubmitChanges();
}
catch (DuplicateKeyException duplicateKeyException)
{
_databaseContext.Dispose();
_databaseContext = new FolderDbContext(FolderDbContext.DBConnectionString);
throw new FolderAlreadyExistsException(duplicateKeyException);
}
return Task.FromResult(true);
}
When I Add new Folder (folder with such name didn't exist before), Commit and then I try add folder with same name DuplicateKeyException is thrown and handled correctly. However after context gets recreated in catch section the next call to Add and Commit folder with same name throws SqlCeException with message: "A duplicate value cannot be inserted into a unique index. [ Table name = Folders,Constraint name = PK_Folders ]". Is that normal behaviour or am I doing something wrong? In what cases DuplicateKeyException is thrown? How to catch SqlCeException? I can't even see System.Data.SqlServerCe namespace.
use reflection to get the type name of the ex eption, if you wish to catch the SqlCeException explicitly:
ex.GetType().Name == "SqlCeException"

Update in sql Ce in window phone 7

In project i user SQL CE, i have Table:
[Table]
public class Article : INotifyPropertyChanged, INotifyPropertyChanging
{
// Define _cid: private field, public property, and database column.
private int _aid;
[Column(DbType = "INT NOT NULL IDENTITY", IsDbGenerated = true, IsPrimaryKey = true)]
public int aid
{
get { return _aid; }
set
{
NotifyPropertyChanging("aid");
_aid = value;
NotifyPropertyChanged("aid");
}
}
// Define nameColor name: private field, public property, and database column.
private int _rid;
[Column]
public int rid
{
get { return _rid; }
set
{
NotifyPropertyChanging("rid");
_rid = value;
NotifyPropertyChanged("rid");
}
}
private string _title;
[Column]
public string title
{
get { return _title; }
set
{
NotifyPropertyChanging("title");
_title = value;
NotifyPropertyChanged("title");
}
}
private string _thumnail;
[Column]
public string thumnail
{
get { return _thumnail; }
set
{
NotifyPropertyChanging("thumnail");
_thumnail = value;
NotifyPropertyChanged("thumnail");
}
}
private string _DesScription;
[Column(DbType = "NTEXT")]
public string DesScription
{
get { return _DesScription; }
set
{
NotifyPropertyChanging("DesScription");
_DesScription = value;
NotifyPropertyChanged("DesScription");
}
}
private int _orderID;
[Column]
public int orderID
{
get { return _orderID; }
set
{
NotifyPropertyChanging("orderID");
_orderID = value;
NotifyPropertyChanged("orderID");
}
}
private string _pubDate;
[Column]
public string pubDate
{
get { return _pubDate; }
set
{
NotifyPropertyChanging("pubDate");
_pubDate = value;
NotifyPropertyChanged("pubDate");
}
}
private string _linkURL;
[Column]
public string linkURL
{
get { return _linkURL; }
set
{
NotifyPropertyChanging("linkURL");
_linkURL = value;
NotifyPropertyChanged("linkURL");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
// Used to notify that a property changed
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region INotifyPropertyChanging Members
public event PropertyChangingEventHandler PropertyChanging;
// Used to notify that a property is about to change
private void NotifyPropertyChanging(string propertyName)
{
if (PropertyChanging != null)
{
PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}
}
#endregion
}
when i Update Colum Thumnail , i have erros :
SQL Server does not handle comparison of NText, Text, Xml, or Image data types
because of special characters into database insert sequence trogn should I use BbType = "NTEXT"
Please Help me !
You could remove this column for concurrency checking by adding [Column(UpdateCheck = UpdateCheck.Never)] to this column.
See this blogpost about Linq to sql concurrency checking: http://blogs.msdn.com/b/matt/archive/2008/05/22/into-to-linq-to-sql-optimistic-concurrency.aspx

Categories

Resources