I'm a Java developer by profession & was given some tasks in .NET as a pilot project.
It's a small invoicing application which needs to be developed with WPF & EntityFramework.
One of my tasks consist of showing a list of invoices in a window and upon clicking "edit" for any invoice, I should show the details of that invoice along with the invoice items that are assigned to that invoice.
Following is my XAML code fragment of showing invoice items.
<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>
Now, what I need to achieve is that when I select a checkbox, the code behind should automatically increase the value of the IntegerUpDown component to 1. Also if I deselect a checkbox, the code behind should automatically reset the value of the IntegerUpDown component to 0.
Following is my code fragment for Product_Selected event.
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
}
}
}
To do this, I need to access the IntegerUpDown component of the selected row. Unfortunately, I have no idea of doing that.
I hope that some of you .NET geniuses may be able to help me in this matter.
Thanks very much in advance.
Reagrds, Asela.
Okay, it's been some time since I answered any questions here, but yours is definitely worth some attention.
First of all, regarding this:
Forget java.
Most (if not all) of the (rather cumbersome and excessively verbose) patterns and paradigms you might be used to in java are of little or no use at all in C# and WPF.
This is because, in constrast to java, C# is a modern, professional-level language with many language features that provide ease of development and greatly reduce boilerplate.
In addition to that, WPF is an advanced, professional-level UI framework with tons of advanced features (most notably Data Binding and Data Templating) that allow you to create a high-level abstraction and completely separate your code and application logic from the UI components, achieving maximum flexibility without introducing nasty constructs or unnecessary coupling.
Such an abstraction is achieved by implementing a pattern called MVVM. This pattern is rather ubiquitous in most (if not all) modern UI technologies, both Web and Non-Web, except in the java world, which instead seems to believe (unsurprisingly) it's still 1990.
So, instead of trying to hammer concepts from legacy technologies and make them somehow fit into WPF, I suggest you take the time to understand, and embrace The WPF Mentality.
Now, I see several flaws in your code, both in terms of the code itself and in terms of the philosophy / approach you're using to write it.
First of all, the presence of things like
Height="464" Margin="444,16,10,0"
or the like in XAML indicate that you used the Visual Studio designer to build such UI. This is useful as a learning exercise, but it is highly discouraged for production code, for the reasons stated here.I suggest you take the time to properly learn XAML and also look at this tutorial to understand how the WPF layout system works, and how to write resolution-independent, auto-adjustable WPF UIs rather than fixed-size, fixed-position layouts that don't properly adjust even when resizing the containing Window.
Again, the typical mistake developers make in WPF when coming from whatever other technologies is in how they approach things, rather than how they code them. Let's analyze your code:
This code (aside from the fact that it could be shortened) is, at first glance, just fine. You're retrieving the underlying data object rather than trying to mess with the UI elements. This IS the correct approach in WPF. You need to operate on your data items and NOT the UI.
Let's rewrite it into a more C#-like way:
Okay, So far so good, but then you slip away from this data-centric thinking into trying to manipulate the UI for some reason.
Think about it: you're trying to "update the
Value
property of theIntegerUpDown
which corresponds to the currently selected row".But, your XAML shows that the
Value
property of theIntegerUpDown
is actually bound via Two-Way DataBinding to a property calledproductQuantity
in the underlying data item.So, basically, your code results in something like this:
See? you're creating a completely unnecessary indirection. Instead, simply operate on your data item rather than the UI, and let Two-Way databinding take care of the rest. That's the WPF mentality.
But it doesn't even end there.
Your XAML also shows that the
CheckBox
you're dealing with has it'sIsChecked
property bound to a property calledselected
in the underlying Data item:This means that your
InvoiceItemsDTO
class has apublic bool selected {...}
property, right? So, instead of dealing with events at the UI level, (again), why don't you simply put the logic where it really belongs, and get rid of the UI dependencies, effectively making your code more testable, much cleaner, and simply beautiful?See? simple, clean, testable, and beautiful, and it just works.
But, How does it work?
1 - When the Checkbox is clicked by the user, the IsChecked value is updated.
2 - WPF's DataBinding updates the value of the
InvoiceItemsDTO.Selected
property totrue
.3 - Your code adds +1 to the
ProductQuantity
property.4 - WPF's DataBinding reflects the
ProductQuantity
change in the UI, provided you have properly ImplementedINotifyPropertyChange
.The same workflow occurs when un-checking the Checkbox, but with
false
value.This removes the need for event handlers, casting, code behind, and other cumbersome approaches that require useless boilerplate and introduce unnecessary, undesired coupling.
Bottom line: C# Rocks. WPF Rocks. java is legacy.
Let me know if you need further help.