当我只想更改1个项目时,DataGrid将所有项目设置为相同的值

时间:2016-04-01 18:43:01

标签: c# wpf datagrid

当我尝试在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控件。

1 个答案:

答案 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()

ManagerAccount都应该实现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将在没有任何网格刷新或任何内容的情况下更新 - 它只会知道。很方便。