Selected Index Change on WPF combobox? - wpf

I'm converting an app of mine from WinForms to WPF. I came across this problem where in WinForms if I CLEAR a combobox, that does not fire combobox.selectedindexchange. It only fires when the user actually changes the index.
That's the functionality I need. However in WPF I can only find combobox.SelectionChanged. This unfortunately fires on both index change and clearing a combobox (any change).
In WPF how can I only trigger an event when the user changes the index? I'm assuming there's a solution I'm missing that's like the WinForms solution. I'm trying not to play games with global variables and having to track what was previously selected....that's a mess.
Mouseleave is also a mess.
I would greatly appreciate any help!

In your case you can implement in SelectionChanged event:
Private Sub OnSelectionChanged(sender As System.Object, e As System.Windows.Controls.SelectionChangedEventArgs)
Dim combo = TryCast(sender, ComboBox)
If combo.SelectedItem IsNot Nothing Then
'do something
End If
End Sub

You can remove event handler, invoke clear method and add again event handler.
Example code:
<StackPanel>
<ComboBox Name="myCB"
SelectionChanged="ComboBox_SelectionChanged">
<ComboBoxItem>test1</ComboBoxItem>
<ComboBoxItem>test2</ComboBoxItem>
<ComboBoxItem>test3</ComboBoxItem>
</ComboBox>
<Button Content="Clear" Click="Button_Click" />
</StackPanel>
MainWindow class:
Class MainWindow
Private Sub ComboBox_SelectionChanged(sender As System.Object, e As System.Windows.Controls.SelectionChangedEventArgs)
Console.WriteLine("Selected index: {0}", CType(sender, ComboBox).SelectedIndex)
End Sub
Private Sub Button_Click(sender As System.Object, e As System.Windows.RoutedEventArgs)
RemoveHandler Me.myCB.SelectionChanged, AddressOf ComboBox_SelectionChanged
Me.myCB.Items.Clear()
AddHandler Me.myCB.SelectionChanged, AddressOf ComboBox_SelectionChanged
End Sub
End Class

Related

How to create a custom Textbox in WPF?

I am new to wpf
I want to create a custom textbox with the features such as
Change background color or Change Border Darker/Lighter on GotFocus and LostFocus.
Write only in UPPER CASE
WaterMark
Rounded Corner
I found code for rounded corner in XAML and it works good.
Following is the code :
<TextBox x:Name="txtUserName" BorderThickness="1" Height="23">
<TextBox.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="3"/>
</Style>
</TextBox.Resources>
</TextBox>
I use to code in VB.NET Winforms before and I did something like this in there.
I made a class say MainTextBoxex
Public Class MainTextboxex
Inherits TextBox
Private Sub MainTextBoxEx_Enter(sender As Object, e As EventArgs) Handles Me.Enter
Me.BackColor = Color.FromArgb(247, 180, 65)
'Me.SelectAll()
End Sub
Private Sub MainTextBoxEx_Leave(sender As Object, e As EventArgs) Handles Me.Leave
Me.BackColor = Color.White
End Sub
Public Sub New()
MyBase.New()
Me.CharacterCasing = CharacterCasing.Upper
End Sub
Private Sub MainTextboxex_KeyPress(sender As Object, e As KeyPressEventArgs) Handles Me.KeyPress
If e.KeyChar = ChrW(39) Then e.KeyChar = ChrW(96)
End Sub
Private NotInheritable Class NativeMethods
Private Sub New()
End Sub
Private Const ECM_FIRST As UInteger = &H1500
Friend Const EM_SETCUEBANNER As UInteger = ECM_FIRST + 1
<DllImport("user32.dll", EntryPoint:="SendMessageW")>
Public Shared Function SendMessageW(hWnd As IntPtr, Msg As UInteger, wParam As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> lParam As String) As IntPtr
End Function
End Class
Private _watermark As String
Public Property Watermark() As String
Get
Return _watermark
End Get
Set(value As String)
_watermark = value
UpdateWatermark()
End Set
End Property
Private Sub UpdateWatermark()
If IsHandleCreated AndAlso _watermark IsNot Nothing Then
NativeMethods.SendMessageW(Handle, NativeMethods.EM_SETCUEBANNER, CType(1, IntPtr), _watermark)
End If
End Sub
Protected Overrides Sub OnHandleCreated(e As EventArgs)
MyBase.OnHandleCreated(e)
UpdateWatermark()
End Sub
End Class
This worked awesome in winforms as I needed. (No rounded corners in there)
I just need to know how it is done here.
I want something that I don't have to code it everytime or for every Individual TextBox for the above feature everywhere.
Just use this custom TextBox and all set.
This will help me alot.
Thank You.
Use UserControls and CustomControls depending on how much deep you want to dive in your customization.
You can add your own properties by using "Dependency Property", and about the events you can expose Action Events and pass them through your Controls Action events.

reflect values to combo box from datagrid on Selection Changed event

I have a combobox and textbox using which values are filled into DataGridViewfor display purpose.
The datagriduses SelectionChanged event.
I am Trying to reflect the same data (when the user moves keys up and down or on mouse click) onto the combobox and textbox on SelectionChanged event of datagrid
Private Sub DataGridView1_SelectionChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DataGridView1.SelectionChanged
combobox.Text = DataGridView1.CurrentRow.Cells("DatabaseTable_ColumnName1").Value.ToString()
textbox.Text = DataGridView1.CurrentRow.Cells("DatabaseTable_ColumnName2").Value.ToString()
End Sub
Above code works fine for textbox but not for combobox.
In case of combobox, it reflects data of initially selected row only and not the rest.
How do I fix this?
i guess you have to use this code for combobox
combobox1.items.add('your string here')
in your situation would be like this :
Private Sub DataGridView1_SelectionChanged(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles DataGridView1.SelectionChanged
combobox1.items.add(DataGridView1.CurrentRow.Cells("DatabaseTable_ColumnName1").Value.ToString())
textbox.Text = DataGridView1.CurrentRow.Cells("DatabaseTable_ColumnName2").Value.ToString()
End Sub

What is the correct Xaml syntax (and underlying vb code) to have a event raised by a custom Control handled in a host application view model

I have a wpf Custom Control which is now raising custom events. In a test project that I have created to test the ongoing development of the control I have placed a copy of my new custom control on the main window.
In the properties dialog for said control I can see my new event and I can type in the name for a handler for it in the code behind the main window and it's not only created for me but when I place a break point on it I see both the sender and my own event args raised in the control.
What I would now like to know Is what is the correct way to alert a viewmodel about that event respecting the principles of MVVM.
Below is the xaml markup for my custom control in the mainwindow of the test application
<WpfControls:VtlDataNavigator Name="vtlDn"
ItemsSource="{Binding Path=Orders}"
Grid.Row="1"
AddButtonVisibility="True"
CancelNewRecordButtonVisibility="True"
SaveButtonVisibility="True" />
The event I want to catch is called 'RecordControlButtonClicked' and this is the event automatically created in the mainwindow code behind
Private Sub MyCustomHandlerForControlEvent(sender As Object, e As ViewToLearn.WpfControls.VtlDataNavigatorEventArgs) Handles vtlDn.RecordControlButtonClicked
End Sub
So now what I'm after is the correct syntax in both the xaml and my new MainWindowViewModel to have this event transferred across to the viewmodel for handling (or suggestions as to the most efficient way to do this idf there is no direct route.
FYI I already have a relay command set up in the test application but the way that I've used it to bind commands in the past doesn't appear to be working with events.
Edit
One approach I've tried which appears to work is to add the following in the code behind of the main window's loaded event.
Class MainWindow
Public Sub New()
InitializeComponent
DataContext = New MainWindowViewModel
End Sub
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
Dim mvm As MainWindowViewModel = DirectCast(DataContext, MainWindowViewModel)
mvm.vtldn = vtlDn
End Sub
End Class
and then add the following in the viewmodel;
Private _vtldn As ViewToLearn.WpfControls.VtlDataNavigator
Public Property vtldn As ViewToLearn.WpfControls.VtlDataNavigator
Get
Return _vtldn
End Get
Set(ByVal Value As ViewToLearn.WpfControls.VtlDataNavigator)
If (_vtldn Is Value) Then Return
If Not IsNothing(vtldn) Then
RemoveHandler vtldn.RecordControlButtonClicked, AddressOf MyCustomHandler
End If
_vtldn = Value
If Not IsNothing(vtldn) Then
AddHandler vtldn.RecordControlButtonClicked, AddressOf MyCustomHandler
End If
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(NameOf(vtldn)))
End Set
End Property
Private Sub MyCustomHandler(ByVal sender As Object, ByVal e As VtlDataNavigatorEventArgs)
'this does get called when buttons in the custom control are clicked
End Sub
However I'm acutely aware that this is not really 'pure' mvvm so if there are better ways to do this I'm open to suggestions.

Event not fired .NET / XAML

I have a button and when it is clicked, an event should be raised. I declare the event in one class, but I invoke it in another.
Here is my code:
XAML:
<Button x:Name="btnAddUsers" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,15,60" Padding="5,0,5,0" Click="ImportButton_Click" Content="Add"></Button>
Event declaration and the Click method:
Public Event GettingADUsers()
Private Sub ImportButton_Click(sender As Object, e As RoutedEventArgs) Handles btnADAddUsers.Click
RaiseEvent GettingADUsers()
End Sub
In another class I invoke the event (I invoke it in the constructor):
AddHandler StaffSettings.GettingADUsers, AddressOf ctlStaff_GettingAllUsers
And the method:
Private Sub ctlStaff_GettingAllUsers()
adUsers.Load()
End Sub
Do I miss something?

WPF: Databinding and the keypress handlers

This is my textbox:
<TextBox TextAlignment="Right" Text="{Binding PriorityScore, StringFormat=N2}"
Name="PriorityScoreBox" TextChanged="PriorityScoreBox_TextChanged" />
When I click on the Save button everything works fine.
When I press Control-S, it doesn't save the pending changes in the textbox. This is done via a page-level key press handler.
I cannot use UpdateSourceTrigger=PropertyChanged because it interfers with the string formatting. (The user types "4" and the box auto-changes to "4.00".)
Perhaps there is a way to commit the outstanding changes in a key press event?
Private Sub PriorityScoreBox_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Input.KeyEventArgs)
If e.Key = Input.Key.S And CBool(e.KeyboardDevice.Modifiers And ModifierKeys.Control) Then
Dim bx As BindingExpression = CType(sender, TextBox).GetBindingExpression(TextBox.TextProperty)
bx.UpdateSource()
End If
End Sub

Resources