Print input from user in WPF VB - wpf

I'm working on project where the user will enter a JobNumber, say (J000001), and when the user hits print the jobnumber will print. With the code below, I'm able to print the numbers, say (001), but I want the user to enter the actual JobNumber (J000001). Any help on this is greatly appreciated.
When I enter the JobNumber (J000001), I get the following error message:
'Invalid CastException was unhandled'
Conversion from string "J000001" to type boolean is not valid.
Below is my VB Code:
Imports System.Globalization
Imports System.Drawing.Printing
Imports System.Drawing
Class MainWindow
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
AddHandler printDocument1.PrintPage, AddressOf printDocument1_PrintPage
End Sub
'Declaration the global variables
Private paperSize As New PaperSize("papersize", 300, 500)
'set the paper size
Private totalnumber As Integer = 0
'this is for total number of items of the list or array
Private itemperpage As Integer = 0
'this is for no of item per page
Private printDocument1 As New PrintDocument()
Private printDialog1 As New System.Windows.Forms.PrintDialog()
Private DefaultFont As New Font("Calibri", 20)
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
If txtStart.Text Then
itemperpage = 1
totalnumber = txtStart.Text
printDialog1.Document = printDocument1
printDocument1.DefaultPageSettings.PaperSize = paperSize
printDialog1.ShowDialog()
'printDocument1.PrinterSettings.PrinterName = "";
printDocument1.Print()
Else
MessageBox.Show("Invalid number")
End If
End Sub
Private Function CheckNumber(str As String)
Dim Num As Double
Return Double.TryParse(str, Num)
End Function
'Define the Printpage event of the printdocument
Private Sub printDocument1_PrintPage(sender As Object, e As System.Drawing.Printing.PrintPageEventArgs)
Dim currentY As Single = 10
While totalnumber <= CInt(txtStart.Text)
' check the number of items
e.Graphics.DrawString(totalnumber.ToString(), DefaultFont, System.Drawing.Brushes.Black, 50, currentY)
'print each item
currentY += 20
' set a gap between every item
totalnumber += 1
'increment count by 1
If itemperpage < 1 Then
' check whether the number of item(per page) is more than 1 or not
itemperpage += 1
' increment itemperpage by 1
' set the HasMorePages property to false , so that no other page will not be added
e.HasMorePages = False
Else
' if the number of item(per page) is more than 1 then add one page
itemperpage = 1
'initiate itemperpage to 0 .
If totalnumber <= Convert.ToInt32(txtStart.Text) Then
e.HasMorePages = True
End If
'e.HasMorePages raised the PrintPage event once per page .
'It will call PrintPage event again
Return
End If
End While
End Sub
End Class
XAML code
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="175" Width="303">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="1.5*" />
</Grid.ColumnDefinitions>
<Label Content="Start Number:" />
<TextBox x:Name="txtStart" Grid.Column="1" />
<Button Grid.Row="2" Grid.ColumnSpan="2" Content="Print" Click="Button_Click" />
</Grid>
</Window>

The issue is your If statement in the Button_Click method.
If txtStart.Text Then
The If takes a boolean, but you are passing it a string. VB.Net is trying to convert the string to a boolean. 001 works, because it can convert that. J000001 is not able to be converted to a boolean.
Do you mean to check if there is a value entered?
If !String.IsNullOrWhiteSpace(txtStart.Text) Then
You will also run into a similar issue when assigning the value to totalnumber.

You are comparing the value of the text box as a boolean, and then assigning the value of your Text Box to a variable of type Integer.
If txtStart.Text Then
should probably be something like:
If !String.IsNullOrEmpty(txtStart.Text) Then
And then if you job numbers are alpha numeric, use a variable of type String instead of Integer.

Related

WPF NumericUpDown usercontrol in VB.net

I am creating my own NumericUpDown control in VB. Here is my XAML:
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
x:Class="NumericUpDown"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="100">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="20" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<TextBox x:Name="txtNum" Grid.Column="0" x:FieldModifier="private" TextChanged="txtNum_TextChanged"/>
<Button x:Name="cmdDown" Grid.Column="1" x:FieldModifier="private" Content="˅" Width="20" Click="cmdDown_Click" />
<Button x:Name="cmdUp" Grid.Column="2" x:FieldModifier="private" Content="˄" Width="20" Click="cmdUp_Click" />
</Grid>
</UserControl>
And here is the VB code behind it:
Class NumericUpDown
Dim _Minimum As Double = 0
Dim _Maximum As Double = 100
Private Sub NumericUpDown()
InitializeComponent()
txtNum.Text = Numeric
End Sub
Public Property Maximum As Double
Get
Return _Maximum
End Get
Set(value As Double)
_Maximum = value
End Set
End Property
Public Property Minimum As Double
Get
Return _Minimum
End Get
Set(value As Double)
_Minimum = value
End Set
End Property
Public Shared ReadOnly NumericProperty As DependencyProperty = DependencyProperty.Register("Numeric", GetType(String), GetType(NumericUpDown), _
New PropertyMetadata(""))
Public Property Numeric As String
Get
Return CType(GetValue(NumericProperty), String)
End Get
Set(value As String)
SetValue(NumericProperty, value)
End Set
End Property
Private Sub cmdUp_Click(sender As Object, e As RoutedEventArgs)
Dim NumValue As Double
NumValue = Val(txtNum.Text)
NumValue += 1
If NumValue > Maximum Then NumValue = Maximum
txtNum.Text = NumValue.ToString
End Sub
Private Sub cmdDown_Click(sender As Object, e As RoutedEventArgs)
Dim NumValue As Double
NumValue = Val(txtNum.Text)
NumValue -= 1
If NumValue < Minimum Then NumValue = Minimum
txtNum.Text = NumValue.ToString
End Sub
Private Sub txtNum_TextChanged(sender As Object, e As TextChangedEventArgs)
Numeric = txtNum.Text
End Sub
End Class
I use it in my page like this:
Put this on page definition:
xmlns:local="clr-namespace:Demo"
And put this in the content section:
<local:NumericUpDown Numeric="{Binding Path=score, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
Of course I have already set DataContext on the container and all other databound controls work as they should. But the textbox in my custom control turned out empty! It doesn't end here. When I type something in the textbox and when I give it some value using decrease and increase button, the value is transferred to my DataTable; which means this usercontrol does work to some extend. Where did I do wrong? Why won't the Textbox content be initialized with the starting value?
After a little more testing. It seems that my usercontrol doesn't work in 'Two-Way'. It doesn't receive data from DataTable, it only propagates value to it. How do I fix it?
The issue is that you are not binding the Text property of txtNum to your Numeric property.
<TextBox x:Name="txtNum" Grid.Column="0" x:FieldModifier="private"
Text="{Binding Path=Numeric, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"/>
Then you can remove txtNum_TextChanged, and modify your up/down click handlers to just update the Numeric property, e.g.:
Private Sub cmdUp_Click(sender As Object, e As RoutedEventArgs)
If Me.Numeric < Me.Maximum Then
Me.Numeric += 1
Else
Me.Numeric = Me.Maximum
End If
End Sub
Private Sub cmdDown_Click(sender As Object, e As RoutedEventArgs)
If Me.Numeric > Me.Minimum Then
Me.Numeric -= 1
Else
Me.Numeric = Me.Minimum
End If
End Sub
Note that there are still lots of issues - a user can enter a value outside of the allowed range, or non-numeric data (which will break things!), etc. For this specific problem, you could check out the Extended EPF Toolkit, which has various up/down controls.

How to bind object to UserControl?

I have a CustomerOrder class which has 2 properties namely CustomerName and NumberOfOrders. I have a Usercontrol to show these two properties, namely ucCustomerOrder.
Following the code corresponding
Customer Class
Public Class CustomerOrder
Private m_CustomerName As String = String.Empty
Private m_NumberOfOrders As Decimal = 0
Public Property CustomerName As String
Get
Return m_CustomerName
End Get
Set(ByVal value As String)
m_CustomerName = value
End Set
End Property
Public Property NumberOfOrders As Decimal
Get
Return m_NumberOfOrders
End Get
Set(ByVal value As Decimal)
m_NumberOfOrders = value
End Set
End Property
End Class
UserControl XAML
<UserControl x:Class="ucCustomerOrder"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="99" d:DesignWidth="300">
<Grid>
<Label Name="lblCustomerName" Content="{Binding Path=CustomerName}" Height="28" HorizontalAlignment="Left" Margin="23,12,0,0" VerticalAlignment="Top" Width="237" />
<Label Name="lblNoOfOrders" Content="{Binding Path=NumberOfOrders}" Height="28" HorizontalAlignment="Left" Margin="23,46,0,0" VerticalAlignment="Top" Width="237" />
</Grid>
</UserControl>
Code behind the User control is as follows.
Public Class ucCustomerOrder
Private m_CustomerOrder As CustomerOrder
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
m_CustomerOrder = New CustomerOrder
Me.DataContext = m_CustomerOrder
End Sub
Public Property CustomerOrder As CustomerOrder
Get
Return m_CustomerOrder
End Get
Set(ByVal value As CustomerOrder)
m_CustomerOrder = value
Me.DataContext = m_CustomerOrder
End Set
End Property
End Class
In my main window I have a combo box control and ucCustomerOrder (User Control) and also I have list of Customer’s orders in Dictionary object. Like as follows
XAML For main windows looks like
<Window x:Class="DictionaryTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DictionaryTest" Height="182" Width="300" xmlns:my="clr-namespace:TestUserControls">
<Grid>
<ComboBox Height="23" Width="254" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="12,12,0,0" Name="cboCustomerOrders" ItemsSource="{Binding}" DisplayMemberPath="Key" SelectedValuePath="Value"/>
<my:ucCustomerOrder HorizontalAlignment="Left" VerticalAlignment="Top" Margin="12,56,0,0" x:Name="UcCustomerOrder1"/>
</Grid>
</Window>
Code Behind for my main window as follows.
Public Class DictionaryTest
Private Function GetCustomers() As Dictionary(Of String, CustomerOrder)
Dim customerList As New Dictionary(Of String, CustomerOrder)
Dim customer1 As New CustomerOrder
With customer1
.CustomerName = "XXXX"
.NumberOfOrders = 100
End With
Dim customer2 As New CustomerOrder
With customer2
.CustomerName = "ZZZZ"
.NumberOfOrders = 150
End With
customerList.Add("X-Customer", customer1)
customerList.Add("Z-Customer", customer2)
Return customerList
End Function
Private Sub DictionaryTest_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
Try
cboCustomerOrders.ItemsSource = GetCustomers()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
End Class
How can I set my selected CustomerOrder object to the user control using Binding?

WPF Parent Element Lost Focus

I am developing a WPF application. In one of my pages I have a DockPanel with 3 ComboBoxes within it. These 3 ComboBoxes are dependent on each other. So, I have a binding group on the DockPanel and a validation rule for that binding group.
I would like to validate these 3 ComboBoxes when the DockPanel loses focus; however, the DockPanel's LostFocus event is fired when the user clicks on one of the child ComboBoxes within it!
I would have thought that if the child control has focus, the parent control would also have focus...however this does not seem to be the case.
I am looking for a solution to perform validation on the binding group when the DockPanel loses focus...where the focus is lost to a control that is not one of its children.
Edit:
So, I created as simple an application as I could to demonstrate the problem.
I have a "FertilizerCombination" class that contains 3 integers that make up the Fertilizer. These must be unique within the application. Currently the only combination that is not available is 10-10-10. This is a hard coded value in the class.
Public Class FertilizerCombination
Private _nitrogen As Integer
Private _phosphorous As Integer
Private _potassium As Integer
<System.ComponentModel.DataAnnotations.Range(1, 20)> _
Public Property Nitrogen As Integer
Get
Return _nitrogen
End Get
Set(value As Integer)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(value, NitrogenValidationContext)
_nitrogen = value
End Set
End Property
<System.ComponentModel.DataAnnotations.Range(1, 20)> _
Public Property Phosphorous As Integer
Get
Return _phosphorous
End Get
Set(value As Integer)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(value, PhosphorousValidationContext)
_phosphorous = value
End Set
End Property
<System.ComponentModel.DataAnnotations.Range(1, 20)> _
Public Property Potassium As Integer
Get
Return _potassium
End Get
Set(value As Integer)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(value, PotassiumValidationContext)
_potassium = value
End Set
End Property
Public Sub New()
End Sub
Public Sub New(ByVal nitrogen As Integer, ByVal phosphorous As Integer, ByVal potassium As Integer)
Me.Nitrogen = nitrogen
Me.Phosphorous = phosphorous
Me.Potassium = potassium
End Sub
Public Shared Function FertilizerCombinationAvailable(ByVal nitrogen As Integer, ByVal phosphorous As Integer, ByVal potassium As Integer) As Boolean
'Checking against combinations already used'
If nitrogen = "10" And phosphorous = "10" And potassium = "10" Then
'Combination has already been used'
Return False
End If
'Combination was not used yet'
Return True
End Function
Public Sub SetFertilizerCombination(ByVal nitrogen As Integer, ByVal phosphorous As Integer, ByVal potassium As Integer)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(nitrogen, NitrogenValidationContext)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(phosphorous, PhosphorousValidationContext)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(potassium, PotassiumValidationContext)
If FertilizerCombination.FertilizerCombinationAvailable(nitrogen, phosphorous, potassium) = False Then
Throw New ArgumentException("This fertilizer combination has already been used")
End If
Me.Nitrogen = nitrogen
Me.Phosphorous = phosphorous
Me.Potassium = potassium
End Sub
Private NitrogenValidationContext = New System.ComponentModel.DataAnnotations.ValidationContext(Me, Nothing, Nothing) With {.MemberName = "Nitrogen"}
Private PhosphorousValidationContext = New System.ComponentModel.DataAnnotations.ValidationContext(Me, Nothing, Nothing) With {.MemberName = "Phosphorous"}
Private PotassiumValidationContext = New System.ComponentModel.DataAnnotations.ValidationContext(Me, Nothing, Nothing) With {.MemberName = "Potassium"}
End Class
I have a created a Validation Rule for the Fertilizer Combination Class:
Public Class FertilizerCombinationValidationRule
Inherits ValidationRule
Public Overrides Function Validate(ByVal value As Object, ByVal cultureInfo As System.Globalization.CultureInfo) As System.Windows.Controls.ValidationResult
Dim bg As BindingGroup = TryCast(value, BindingGroup)
If bg IsNot Nothing AndAlso bg.Items.Count > 0 Then
'The BindingGroup Items property contains the original object(s)'
Dim fertilizerCombo As FertilizerCombination = TryCast(bg.Items(0), FertilizerCombination)
'Using the BindingGroups GetValue method to retrieve the user provided values'
Dim proposedNitrogen As Integer
Dim proposedPhosphorous As Integer
Dim proposedPotassium As Integer
Try
proposedNitrogen = bg.GetValue(fertilizerCombo, "Nitrogen")
proposedPhosphorous = bg.GetValue(fertilizerCombo, "Phosphorous")
proposedPotassium = bg.GetValue(fertilizerCombo, "Potassium")
If FertilizerCombination.FertilizerCombinationAvailable(proposedNitrogen, proposedPhosphorous, proposedPotassium) = False Then
Return New ValidationResult(False, "This fertializer combination has already been used")
End If
Catch noValue As System.Windows.Data.ValueUnavailableException
'a binding was not properly bound yet'
End Try
End If
Return New ValidationResult(True, Nothing)
End Function
End Class
I have a "PlantSolution" class that has a FertilizerCombination property. I also have a VM for that class so that it's easy for binding in the XAML:
Public Class PlantSolutionVM
Public Property PlantSolution As PlantSolution
Public Sub New()
PlantSolution = New PlantSolution("Produce Blooms", "Using this fertilizer will help your plant produce flowers!", 10, 10, 20)
End Sub
End Class
Public Class PlantSolution
Private _name As String
Private _description As String
Private _fertilizer As FertilizerCombination
<System.ComponentModel.DataAnnotations.Required()>
Public Property Name As String
Get
Return _name
End Get
Set(value As String)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(value, NameValidationContext)
_name = value
End Set
End Property
<System.ComponentModel.DataAnnotations.Required()>
Public Property Description As String
Get
Return _description
End Get
Set(value As String)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(value, DescriptionValidationContext)
_description = value
End Set
End Property
Public ReadOnly Property Fertilizer As FertilizerCombination
Get
Return _fertilizer
End Get
End Property
Public Sub New(name As String, description As String, nitrogen As Integer, phosphorous As Integer, potassium As Integer)
_fertilizer = New FertilizerCombination(nitrogen, phosphorous, potassium)
Me.Name = name
Me.Description = description
End Sub
Private NameValidationContext = New System.ComponentModel.DataAnnotations.ValidationContext(Me, Nothing, Nothing) With {.MemberName = "Name"}
Private DescriptionValidationContext = New System.ComponentModel.DataAnnotations.ValidationContext(Me, Nothing, Nothing) With {.MemberName = "Description"}
End Class
Now here is my XAML for a window called "FunWithFocus":
<Grid>
<Grid.Resources>
<x:Array x:Key="CombinationOptions" Type="sys:Int32" xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:Int32>0</sys:Int32>
<sys:Int32>1</sys:Int32>
<sys:Int32>2</sys:Int32>
<sys:Int32>3</sys:Int32>
<sys:Int32>4</sys:Int32>
<sys:Int32>5</sys:Int32>
<sys:Int32>6</sys:Int32>
<sys:Int32>7</sys:Int32>
<sys:Int32>8</sys:Int32>
<sys:Int32>9</sys:Int32>
<sys:Int32>10</sys:Int32>
<sys:Int32>11</sys:Int32>
<sys:Int32>12</sys:Int32>
<sys:Int32>13</sys:Int32>
<sys:Int32>14</sys:Int32>
<sys:Int32>15</sys:Int32>
<sys:Int32>16</sys:Int32>
<sys:Int32>17</sys:Int32>
<sys:Int32>18</sys:Int32>
<sys:Int32>19</sys:Int32>
<sys:Int32>20</sys:Int32>
</x:Array>
<local:PlantSolutionVM x:Key="PlantSolutionVM" />
<Style TargetType="DockPanel">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid DataContext="{Binding Source={StaticResource PlantSolutionVM}, Path=PlantSolution}" Margin="50">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Solution Name:" Grid.Row="0" Grid.Column="0" Margin="5"/>
<TextBox x:Name="ItemName" Text="{Binding Name, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" Margin="5"/>
<TextBlock Text="Description of Problem:" Grid.Row="1" Grid.Column="0" Margin="5"/>
<TextBox x:Name="ItemDescription" Text="{Binding Description, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Grid.Row="1" Grid.Column="1" Margin="5"/>
<TextBlock Text="Recommended Fertilizer:" Grid.Row="2" Grid.Column="0" Margin="5"/>
<DockPanel x:Name="FertilizerCombinationContainer" DataContext="{Binding Fertilizer}" Grid.Row="2" Grid.Column="1" Margin="5" HorizontalAlignment="Left" VerticalAlignment="Top">
<DockPanel.BindingGroup>
<BindingGroup NotifyOnValidationError="True">
<BindingGroup.ValidationRules>
<local:FertilizerCombinationValidationRule />
</BindingGroup.ValidationRules>
</BindingGroup>
</DockPanel.BindingGroup>
<ComboBox x:Name="NitrogenValue" HorizontalAlignment="Left" VerticalAlignment="Top"
ItemsSource="{StaticResource CombinationOptions}"
SelectedItem="{Binding Nitrogen}"/>
<ComboBox x:Name="PhosphorousValue" HorizontalAlignment="Left" VerticalAlignment="Top"
ItemsSource="{StaticResource CombinationOptions}"
SelectedItem="{Binding Phosphorous}"/>
<ComboBox x:Name="PotatssiumValue" HorizontalAlignment="Left" VerticalAlignment="Top"
ItemsSource="{StaticResource CombinationOptions}"
SelectedItem="{Binding Potassium}"/>
</DockPanel>
<Button x:Name="SaveIt" Content="Save" Grid.Row="3" Grid.Column="1"/>
</Grid>
</Grid>
And here is the Code Behind for the page:
Class FunWithFocus
Private Sub FertilizerCombinationContainer_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles FertilizerCombinationContainer.Loaded
'FertilizerCombinationContainer.BindingGroup.CancelEdit()'
'FertilizerCombinationContainer.BindingGroup.BeginEdit()'
End Sub
Private Sub FertilizerCombinationContainer_LostFocus(sender As Object, e As System.Windows.RoutedEventArgs) Handles FertilizerCombinationContainer.LostFocus
'This will get fired if the user drops down one of the comboboxes'
End Sub
'This is how I am currently handling the lost focus...but it doesn't fire if the user clicks somewhere that doesn't take keyboard focus'
'Private Sub FertilizerCombinationContainer_IsKeyboardFocusWithinChanged(sender As Object, e As System.Windows.DependencyPropertyChangedEventArgs) Handles FertilizerCombinationContainer.IsKeyboardFocusWithinChanged'
' If FertilizerCombinationContainer.IsKeyboardFocusWithin = False Then'
' FertilizerCombinationContainer.BindingGroup.ValidateWithoutUpdate()'
' If Validation.GetErrors(FertilizerCombinationContainer).Count = 0 Then'
' FertilizerCombinationContainer.BindingGroup.CommitEdit()'
' Dim bg As BindingGroup = FertilizerCombinationContainer.BindingGroup'
' Dim fertilizerCombo As FertilizerCombination = bg.Items(0)'
' Dim proposedNitrogen As Integer'
' Dim proposedPhosphorous As Integer'
' Dim proposedPotassium As Integer'
' Try'
' proposedNitrogen = bg.GetValue(fertilizerCombo, "Nitrogen")'
' proposedPhosphorous = bg.GetValue(fertilizerCombo, "Phosphorous")'
' proposedPotassium = bg.GetValue(fertilizerCombo, "Potassium")'
' ''there was a change: set it'
' fertilizerCombo.SetFertilizerCombination(proposedNitrogen, proposedPhosphorous, proposedPotassium)'
' Catch noValue As System.Windows.Data.ValueUnavailableException'
' ''a binding was not properly bound yet'
' End Try'
' End If'
' End If'
'End Sub'
End Class
If you put a break point on the method that handles FertilizerCombinationContainer's LostFocus event, you will notice that it is fired when you select one of the ComboBoxes even though it is a child of the FertilizerContainer element.
Thank you,
-Frinny

Grid.GetRow() always returns 0

I am having trouble getting the row of a WPF grid that a textbox is in.
I have a grid that starts off with one RowDefinition. That row contains an "add" button that adds another rowdefinition to the grid below that row. This new row also contains an "add" button that performs the same function.
The problem I am having is that the function GetRow() always returns 0.
If I declare a button in the XAML that calls the same function, GetRow() returns the correct value. The problem seems to stem from the face that the buttons are created in codebehind.
This is the function that handles the click event of the "add" buttons:
Private Sub btnAddRow_Click(ByVal sender As System.Object, _
ByVal e As System.Windows.RoutedEventArgs)
Dim btnSender As Button = sender
Dim row As Integer
row = Grid.GetRow(btnSender)
AddRow(row)
End Sub
The function "AddRow" adds a new RowDefinition to the grid, the "add" button for that row, and a few other controls (label, textbox, etc).
Private Sub AddRow(ByVal position As Integer)
Dim rd As New RowDefinition()
rd.Height = New GridLength(35, GridUnitType.Pixel)
Me.Height += 35
myGrid.RowDefinitions.Insert(position, rd)
Dim add As New Button
add.Content = "Add Row"
add.HorizontalAlignment = Windows.HorizontalAlignment.Center
add.VerticalAlignment = Windows.VerticalAlignment.Center
AddHandler add.Click, AddressOf btnAddRow_Click
Grid.SetColumn(add, 2)
Grid.SetRow(add, position)
myGrid.Children.Add(add)
End Sub
I found this thread, but using "e.Source" or "e.OriginalSource" did not solve the problem.
Grid.GetRow and Grid.GetColumn keep returning 0
EDIT:
Here is my code. I pulled it out of the project it was in and created a new project for testing.
Class MainWindow
Private Sub btnAddRow_Click(ByVal sender As System.Object, _
ByVal e As System.Windows.RoutedEventArgs)
Dim btnSender As Button = sender
Dim row As Integer
row = Grid.GetRow(btnSender)
row = row + 1
AddRow(row)
End Sub
Private Sub AddRow(ByVal position As Integer)
If (myGrid.RowDefinitions.Count < position) Then
position = myGrid.RowDefinitions.Count
End If
For Each element In (From i As UIElement In myWaypointGrid.Children Where Grid.GetRow(i) >= position Select i).ToList()
Grid.SetRow(element, Grid.GetRow(element) + 1)
Next
Dim rd As New RowDefinition()
rd.Height = New GridLength(35, GridUnitType.Pixel)
Me.Height += 35
myGrid.RowDefinitions.Insert(position, rd)
Dim add As New Button
add.Content = "Add Row " & position
add.HorizontalAlignment = Windows.HorizontalAlignment.Center
add.VerticalAlignment = Windows.VerticalAlignment.Center
AddHandler add.Click, AddressOf btnAddRow_Click
Grid.SetColumn(add, 2)
Grid.SetRow(add, position)
myGrid.Children.Add(add)
End Sub
Private Sub MainWindow_Loaded(ByVal sender As Object, _
ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
AddRow(0)
End Sub
End Class
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid Name="myGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
</Grid>
Thanks for your help.
Are you ever calling the AddRow function prior to the first "Add" button click? Without more code, it's hard to say why this is not working.
Update to reflect the true issue:
You don't do an increment on the position variable which gets passed into this function so all your buttons are being added to row 0. That is why they all return 0 when you call GetRow

Binding multiple progress bars

Referring to screenshot below, I have the following view and viewmodel setup to represent progress bar download. When I add more than 1 downloads to this collection of downloads, it seems that download 1 will overwrite download 2's Progress() public property.
Example below is download 1 is downloading 1MB it will finish first and compared with download 2 downloading 5MB.
When download 1 finish, download 2 (hello2 example below) progress bar just stop there but the bytes are still being downloaded at background until 5MB is reached.
How can I change the code to ensure download 1 does not interfere with download 2's progress bar UI. I've tried modifying Progress() to private but then both progress bar UI is not shown
View
<ItemsControl Name="MyItemsControl" ItemsSource="{Binding GameDownloads}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid DockPanel.Dock="Right">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding GameName}" />
<ProgressBar Grid.Row="0" Grid.Column="1" Minimum="0" Maximum="100" Value="{Binding Progress, Mode=OneWay}" />
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding StatusText}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
DownloadAppViewModel
Public Class DownloadAppViewModel
Inherits ViewModelBase
Private ReadOnly WC As WebClient
Public Sub New(ByVal Name As String, ByVal URL As String, ByVal FileName As String)
_gameName = Name
WC = New WebClient
AddHandler WC.DownloadFileCompleted, AddressOf DownloadCompleted
AddHandler WC.DownloadProgressChanged, AddressOf DownloadProgressChanged
WC.DownloadFileAsync(New Uri(URL), FileName)
End Sub
Private Sub DownloadCompleted(ByVal sender As Object, ByVal e As AsyncCompletedEventArgs)
End Sub
Private Sub DownloadProgressChanged(ByVal sender As [Object], ByVal e As DownloadProgressChangedEventArgs)
If _totalSize = 0 Then
_totalSize = e.TotalBytesToReceive
End If
DownloadedSize = e.BytesReceived
End Sub
Private _gameName As String
Public Property GameName() As String
Get
Return _gameName
End Get
Set(ByVal value As String)
_gameName = value
Me.OnPropertyChanged("GameName")
End Set
End Property
Public ReadOnly Property StatusText() As String
Get
If _downloadedSize < _totalSize Then
Return String.Format("Downloading {0} MB of {1} MB", _downloadedSize, _totalSize)
End If
Return "Download completed"
End Get
End Property
Private _totalSize As Long
Private Property TotalSize() As Long
Get
Return _totalSize
End Get
Set(ByVal value As Long)
_totalSize = value
OnPropertyChanged("TotalSize")
OnPropertyChanged("Progress")
OnPropertyChanged("StatusText")
End Set
End Property
Private _downloadedSize As Long
Private Property DownloadedSize() As Long
Get
Return _downloadedSize
End Get
Set(ByVal value As Long)
_downloadedSize = value
OnPropertyChanged("DownloadedSize")
OnPropertyChanged("Progress")
OnPropertyChanged("StatusText")
End Set
End Property
Public ReadOnly Property Progress() As Double
Get
If _totalSize <> 0 Then
Return 100.0 * _downloadedSize / _totalSize
Else
Return 0.0
End If
End Get
End Property
End Class

Resources