在不使用MVVM的情况下实现双向DataGrid数据绑定

时间:2012-08-28 15:34:57

标签: wpf binding datagrid

我会尽可能清楚地说明这一点,但我很清楚我可能会问错误的问题。我在WPF(.NET 4.0)中有一个datagrd,它绑定到数据集中的数据表。相关的代码隐藏(在窗口加载上运行)是:

// create a connection to Top Trumps database
String cs = ConfigurationManager.ConnectionStrings["csTopTrumps"].ConnectionString;
SqlConnection cn = new SqlConnection(cs);

// create a new dataset
DataSet ds = new DataSet();

// open the connection (not strictly necessary, as the
// data adapter will do this when you use it anyway)
cn.Open();

// fill data table called Cards with contents of tblCard
SqlDataAdapter daCards = new SqlDataAdapter();
daCards.SelectCommand =
new SqlCommand("SELECT * FROM tblCard ORDER BY CardTitle", cn);
daCards.Fill(ds, "Cards");

// now set the data context for the entire window
this.DataContext = ds;

我的数据网格定义开始:

<DataGrid ItemsSource="{Binding Tables[Cards]}"

所有这些都很好,我明白了。我现在想要以两种方式进行数据绑定,以便在datagrid中进行的更改将更新回底层数据库。我知道我可以做到这一点的一种方法是获取已更改行的值,并使用带有Update方法的tableadapter将任何更改写回底层数据库(可能是像SelectedCellsChanged事件或类似事件)。但是,任何这样的方法都难以实现,因为在WPF中代码隐藏中获取单元格值很困难(我的理解是这是错误的方法,因为我应该使用WPF框架,所以帮助我)。

那么......我怎样才能设置双向数据绑定来为我做这项工作?我见过人们提到设置datagrid属性,如:

SelectedItem="{Binding Path=SelectedIndex,Mode=TwoWay}"

但我不明白如何使用数据适配器和数据集。我不想要的是涉及MVVM或模型的任何解决方案,因为我没有使用这些(是的,我可能应该是,我知道)。我还想避免大量复杂的C#代码,涉及可观察的集合,通过控制层次结构的递归搜索来查找父母等等。

我已经搜索了很长时间,我想我所问的确实存在 - 如果没有,请告诉我它没有,并为浪费你的时间而道歉,温柔的读者!

2 个答案:

答案 0 :(得分:0)

我完全不理解你。您希望避免使用WPF框架(可观察的集合,绑定,递归搜索等),但是您希望找到使用WPF框架的方法。

首先你需要这些功能:

public static T GetVisualChild<T>(Visual parent) where T : Visual
{
    T child = default(T);
    int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < numVisuals; i++)
    {
        Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
        child = v as T;
        if (child == null)
        {
            child = GetVisualChild<T>(v);
        }
       if (child != null)
       {
           break;
       }
   }
       return child;
}

public static DataGridRow GetSelectedRow(this DataGrid grid)
{
    return (DataGridRow)grid.ItemContainerGenerator.ContainerFromItem(grid.SelectedItem);
}
public static DataGridRow GetRow(this DataGrid grid, int index)
{
    DataGridRow row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
    if (row == null)
    {
        // May be virtualized, bring into view and try again.
        grid.UpdateLayout();
        grid.ScrollIntoView(grid.Items[index]);
        row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
    }
    return row;
}

public static DataGridCell GetCell(this DataGrid grid, DataGridRow row, int column)
{
    if (row != null)
    {
        DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(row);

        if (presenter == null)
        {
            grid.ScrollIntoView(row, grid.Columns[column]);
            presenter = GetVisualChild<DataGridCellsPresenter>(row);
        }

        DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
        return cell;
    }
    return null;
}

public static DataGridCell GetCell(this DataGrid grid, int row, int column)
{
    DataGridRow rowContainer = grid.GetRow(row);
    return grid.GetCell(rowContainer, column);
}

现在DataGrid实际上有几乎有用的事件。它被称为CellEditEnding。 把它挂起来

private bool isManualEditCommit;
private void yourHandler(
  object sender, DataGridCellEditEndingEventArgs e) 
{
 if (!isManualEditCommit) 
 {
  isManualEditCommit = true;
  DataGrid grid = (DataGrid)sender;
  grid.CommitEdit(DataGridEditingUnit.Row, true);
  isManualEditCommit = false;
 } else {
    /* you can write foreach loop that would loop through all the DataGridCells
      with DataGridCell cell = grid.GetCell(row, col),
      you can recieve value like GetVisualChild<TextBlock>(cell).Text
      and update everything when you're at last value */
 }
}

也读过这个; WPF DataGrid CellEditEnding - DataSet Not Updating Till Row Lost Focus

这很难,但如果您有经验,可以提供更好的代码。 尝试搜索术语数据绑定,datagrid,datagridtemplatecolumn,双向绑定,cellEditEnding。

祝你好运!

答案 1 :(得分:0)

好的,有点晚了,我想我得到了我想要的答案。 datagrid绑定到数据表(在我的实例中)。这意味着您可以获取所选项目(可能是用户双击的行),将其转换为数据行,然后到达您感兴趣的字段。

private void DataGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e)

{

// turn the datagrid selected "item" into a data row
DataRowView dr = dg.SelectedItem as DataRowView;

// get at the value for any field (here it's the one called CARD) in the underlying datatable
string CardTitle = (string)dr["Card"];

// display it ...
MessageBox.Show("You are on card " + CardTitle);

}

这将解决双击数据网格中的行的问题,这也是我的想法。如果您正在使用类,则可以将所选项目转换为相关对象,并获取其属性。

我希望这有助于某人!