我是专业的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。
答案 0 :(得分:1)
好的,自从我在这里回答任何问题以来已经有一段时间了,但你的确值得关注。
首先,关于这个:
我是专业的Java开发人员
忘记java。
在Java中,大多数(如果不是全部)(相当繁琐且过于冗长)的模式和范例在C#和WPF中几乎没有用或根本没有用。
这是因为,与Java相比,C#是一种现代的专业级语言,具有许多语言功能,易于开发并大大减少了样板。
除此之外,WPF是一个先进的专业级UI框架,具有大量高级功能(最值得注意的是Data Binding和Data 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是遗产。
如果您需要进一步的帮助,请告诉我。