访问DataGrid中列的组件

时间:2014-09-02 13:47:42

标签: c# wpf xaml datagrid integerupdown

我是专业的Java开发人员。在.NET中作为试点项目获得了一些任务。

这是一个小型发票应用程序,需要使用WPF& amp;的EntityFramework。

我的一项任务包括在窗口中显示发票清单,然后点击"编辑"对于任何发票,我应该显示该发票的详细信息以及分配给该发票的发票项目。

以下是显示发票项目的XAML代码片段。

<DataGrid x:Name="ProductGrid" AutoGenerateColumns="False" HorizontalAlignment="Stretch" 
            HorizontalContentAlignment="Stretch" ColumnWidth="*" Height="464" VerticalAlignment="Top" Margin="444,16,10,0" CanUserAddRows="false">
    <DataGrid.Columns>
        <DataGridTemplateColumn Width="55" Header="Selected">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox Margin="2,0,2,0" HorizontalAlignment="Center" VerticalAlignment="Center" 
                                Checked="Product_Selected" Unchecked="Product_Deselected" IsChecked="{Binding Path=selected}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Width="60" Header="Quantity">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <xctk:IntegerUpDown x:Name="UPDOWN" Increment="1" Minimum="0" HorizontalAlignment="Center" ValueChanged="Quantity_Changed" 
                                        VerticalAlignment="Center" Width="50" Value="{Binding productQuantity, Mode=TwoWay}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTextColumn Header="Product Name" Width="250" Binding="{Binding Path=productName}"/>
        <DataGridTextColumn Header="Weight" Binding="{Binding Path=productWeight}"/>
        <DataGridTextColumn Header="Size" Binding="{Binding Path=productSize}"/>
        <DataGridTextColumn Header="Sale price" Binding="{Binding Path=productSalePrice}"/>
    </DataGrid.Columns>
</DataGrid>

现在,我需要实现的是当我选择一个复选框时,后面的代码应该自动将IntegerUpDown组件的值增加到1.如果我取消选中一个复选框,后面的代码应该自动重置该值IntegerUpDown组件为0。

以下是我的Product_Selected事件的代码片段。

private void Product_Selected(object sender, RoutedEventArgs e)
{
    var currRow = ProductGrid.CurrentItem; // Current row

    InvoiceItemsDTO sel = (InvoiceItemsDTO)currRow; // Current row DTO OBJECT
    if (sel != null)
    {
        if (sel.productQuantity == 0) // The user is trying to assign a new item to the invoice
        {
            int currentRowIndex = ProductGrid.Items.IndexOf(currRow); // Current row index
            DataGridRow currentRow = ProductGrid.ItemContainerGenerator.ContainerFromIndex(currentRowIndex) as DataGridRow;

            IntegerUpDown prop = ProductGrid.Columns[1].GetCellContent(currentRow) as IntegerUpDown; // Here I get a NULL for "prop"..!! :(
            prop.Value = 1; // Automatically increase the value of IntegerUpDown from zero to one
        }
    }
}

为此,我需要访问所选行的IntegerUpDown组件。不幸的是,我不知道这样做。

我希望你们中的一些.NET天才能够在这件事上帮助我。

非常感谢。

Reagrds, Asela。

1 个答案:

答案 0 :(得分:1)

好的,自从我在这里回答任何问题以来已经有一段时间了,但你的确值得关注。

首先,关于这个:

  

我是专业的Java开发人员

忘记java。

在Java中,大多数(如果不是全部)(相当繁琐且过于冗长)的模式和范例在C#和WPF中几乎没有用或根本没有用。

这是因为,与Java相比,C#是一种现代的专业级语言,具有许多语言功能,易于开发并大大减少了样板。

除此之外,WPF是一个先进的专业级UI框架,具有大量高级功能(最值得注意的是Data BindingData Templating),可以让您完全创建高级抽象将您的代码和应用程​​序逻辑与UI组件分开,实现最大的灵活性,而不会引入令人讨厌的结构或不必要的耦合。

这种抽象是通过实现一个名为MVVM的模式来实现的。这种模式在大多数(如果不是全部)现代UI技术中无处不在,包括Web和非Web,除了java世界,它似乎相信(不出所料)它仍然是1990年。

因此,我建议你花点时间去理解并拥抱The WPF Mentality,而不是试图从传统技术中剔除概念并使它们适合WPF,我建议你采用here

现在,我在代码中看到了一些缺陷,包括代码本身以及您用来编写它的哲学/方法。

首先,XAML中存在诸如Height="464" Margin="444,16,10,0"之类的内容表明您使用Visual Studio设计器来构建此类UI。这对于学习练习很有用,但由于this tutorial所述的原因,对于生产代码非常不鼓励。

我建议您花时间正确学习XAML,并查看as operator以了解WPF布局系统的工作原理,以及如何编写与分辨率无关,可自动调整的WPF UI而不是固定大小的UI,固定位置布局即使在调整包含窗口的大小时也不能正确调整。

同样,开发人员在使用其他任何技术时在WPF中所犯的典型错误在于他们如何处理事物,而不是他们如何编码。让我们分析您的代码:

 var currRow = ProductGrid.CurrentItem; // Current row

 InvoiceItemsDTO sel = (InvoiceItemsDTO)currRow; // Current row DTO OBJECT

 if (sel != null)
 {
    //...
 }

这段代码(除了它可以缩短的事实)乍一看就好了。您正在检索基础数据对象,而不是试图弄乱UI元素。这是WPF中的正确方法。您需要使用数据项而不是UI。

让我们将它改写成更像C#的方式:

var row = ProductGrid.CurrentItem as InvoiceItemsDTO;
if (row != null)
{
   //...
}
  

注意:以上代码显示了C#语言级功能(在本例中为bunch of horrible hacks)如何帮助减少样板(我们现在有2行代码而不是3)允许漂亮的代码,否则需要Implemented INotifyPropertyChange等劣等技术,如java。

好的,到目前为止一切都那么好,但是后来你从这个以数据为中心的想法试图操纵UI出于某种原因。

想一想:您正在尝试&#34;更新Value的{​​{1}}属性,该属性对应于当前选定的行& #34;

但是,您的XAML通过双向数据绑定显示IntegerUpDown的{​​{1}}属性实际上是绑定 指向基础数据项中名为Value的属性。

因此,基本上,您的代码会产生如下结果:

IntegerUpDown

请参阅?你正在创造一个完全不必要的间接。相反,只是对您的数据项而不是UI进行操作,让双向数据绑定处理其余部分。这就是WPF的心态。

productQuantity
  

了解当您处理现代科技时,生活会变得多么轻松?

但它甚至还没有结束。

您的XAML还会显示您正在处理的get Data Item -> get UI item -> update UI item -> DataBinding updates Data Item. 将其var row = ProductGrid.CurrentItem as InvoiceItemsDTO; if (row != null) { row.productQuantity++; } 属性绑定到基础数据项中名为CheckBox的属性:< / p>

IsChecked

这意味着您的selected班级有<CheckBox [...] IsChecked="{Binding Path=selected}"/> 个属性,对吧?因此,不再在UI级别处理事件(再次),为什么不简单地将逻辑放在它真正属于的位置,并且摆脱UI依赖关系,有效地使您的代码更可测试,更清洁,更美观?

InvoiceItemsDTO
  

另外,请注意使用合适的外壳。 camelCasing非常糟糕,因此只为C#中的public bool selected {...}成员保留。不是public class InvoiceItemsDTO { private bool _selected; public bool Selected { get { return _selected; } set { _selected = value; //This is where your code should be. if (value) ProductQuantity++; else ProductQuantity--; } } } 个。

请参阅?简单,干净,可测试,美观,只是有效

但是, 如何运作?

1 - 当用户点击复选框时,IsChecked值会更新。

2 - WPF的DataBinding将private属性的值更新为public

3 - 您的代码会为InvoiceItemsDTO.Selected属性添加+1。

4 - 只要您有正确的{{3}},WPF的DataBinding就会反映用户界面中的true更改。

取消勾选复选框时会出现相同的工作流程,但值为ProductQuantity

这消除了对事件处理程序,转换,代码隐藏以及其他繁琐的方法的需求,这些方法需要无用的样板并引入不必要的,不期望的耦合。

底线: C#Rocks。 WPF Rocks。 java是遗产。

如果您需要进一步的帮助,请告诉我。