当我尝试在dataGrid中设置特定的Item时,它会将所有其他项的值更改为相同的值。我不确定这是一个错误还是我做错了什么。这是我的代码: (Datagrid在另一个窗口(主窗口),所以我在该窗口中调用了一个函数来编辑值)
private void AAbutton1_Click(object sender, RoutedEventArgs e)
{
Account selected = new Account();
if (textBox2.Text != null)
selected.username = textBox2.Text;
if (textBox12.Text != null)
selected.password = textBox12.Text;
if (locationTxtBox2.Text != null)
selected.location = locationTxtBox2.Text;
MainWindow.Instance.editAccount(selected);
MainWindow.Instance.updateData();
MainWindow.Instance.needsSave = true;
}
这是主窗口中的功能:
public void editAccount(Account acc)
{
Account acc2;
Account selected = (Account)dataGrid.SelectedItem;
acc2 = Manager.accounts.ElementAt(Manager.accounts.FindIndex(a=> a == selected));
acc2.username = acc.username;
acc2.password = acc.password;
acc2.location = acc.location;
}
我真的找不到解决这个问题的方法。
如果您需要,这里是Account类:
public class Account
{
public String username { get; set; }
public String password { get; set; }
public String location { get; set; }
public Account(String username,String password, String location)
{
this.username = username;
this.password = password;
this.location = location;
}
public Account()
{
}
}
提一下,我使用的是Mahapps.metro控件。
答案 0 :(得分:1)
我是对的!我读了你的想法。
这不是WPF问题,绑定问题或DataGrid问题。这是“C#中的引用如何工作?”题。这是一个很好的问题。
在文件加载时,您从加密帐户列表开始,但在解密时,您将每个帐户的所有解密属性复制到同一个帐户实例中,并将该实例多次添加到列表中。解密的都是相同的实例。你开始没问题,但是你在DecryptAccounts()中脱轨了。
这是错误:
public static void DecryptAccounts()
{
// Hmmm. What's he planning to do with this?
Account holder = new Account(null, null, null);
accounts.Clear();
foreach (Account acc in Encryptedaccounts)
{
// HERE IT IS. This is the same instance of holder on every
// iteration. After file load, every Account in accounts is the
// same object as every other.
// You need to create a new Account object for each account.
holder.username = Decrypt(acc.username, user.Decryptedpassword);
holder.password = Decrypt(acc.password, user.Decryptedpassword);
holder.location = Decrypt(acc.location, user.Decryptedpassword);
accounts.Add(holder);
}
}
public static void LoadFromFile()
{
if (File.Exists(Path.Combine(appdata, folder, file)))
{
Encryptedaccounts = JsonConvert.DeserializeObject<List<Account>>(File.ReadAllText(Path.Combine(appdata, folder, file)));
}
DecryptAccounts();
}
Manager.cs
public Account DecryptAccount(Account acc)
{
return new Account {
username = Decrypt(acc.username, user.Decryptedpassword),
password = Decrypt(acc.password, user.Decryptedpassword),
location = Decrypt(acc.location, user.Decryptedpassword)
};
}
public static void DecryptAccounts()
{
accounts.Clear();
foreach (Account acc in Encryptedaccounts)
{
accounts.Add(DecryptAccount(acc));
}
}
// You've got the same issue here
private static void EncryptAccounts()
{
Encryptedaccounts.Clear();
foreach (Account acc in accounts)
{
Encryptedaccounts.Add(EncryptAccount(acc));
}
}
public Account EncryptAccount(Account acc)
{
return new Account {
username = Encrypt(acc.username, user.Decryptedpassword),
password = Encrypt(acc.password, user.Decryptedpassword),
location = Encrypt(acc.location, user.Decryptedpassword)
};
}
其他一些问题在这里。不是错误,但如果你做了“适当的WPF方式”,生活会更容易:
Manager.accounts
应为ObservableCollection<Account>
类型。然后,无论何时添加或删除项目,它都会自动通知DataGrid,您不必一直手动刷新网格updateData()
。
Manager
和Account
都应该实现INotifyPropertyChanged
并在其值更改时触发其属性的通知。在C#6中,这非常简单:
using System.Runtime.CompilerServices;
using System.ComponentModel;
// ... snip ...
public event PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
然后你的属性看起来像这样:
private String _username = null;
public String username {
get { return _username; }
set {
if (value != _username)
{
_username = value;
OnPropertyChanged();
}
}
}
当他们这样做时,无论何时更改值,都会通知您在UI中绑定它们的任何内容。您将能够在所选网格项上设置属性,并且UI将在没有任何网格刷新或任何内容的情况下更新 - 它只会知道。很方便。