Validation in Lost focus event - wpf

we are having wpf pages which has a menu items on the top with select,save,clear,exit items. Below the menu we have got a textbox which accepts the supplier code. In the lost focus of the textbox we have to validate the supplier code is correct and at the same time if user clicks the exit menu item this validation should not happen. this has been easily achieved by checking the tab index in the windows application but in WPF pages we dont know how to achieve.Below code is done in the windows application.same functionality we need in the wpf pages.
we need code in c#
Private Sub txtSupp_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtSupp.Leave
If Me.ActiveControl Is Nothing Then Exit Sub
If Me.ActiveControl.TabIndex <= txtSupp.TabIndex And _
Me.ActiveControl.Parent.TabIndex <= txtSupp.Parent.TabIndex Then Exit Sub
Dim lsErrmsg As String
cowSIMaintain.Validate_Supp(Me, lsErrmsg)
End Sub

private void txtSupp_LostFocus(object sender, RoutedEventArgs e)
{
var focusedControl = Keyboard.FocusedElement;
if (focusedControl.GetType() == typeof(Button))
{
var but = focusedControl as Button;
if (but == null)
{
return;
}
if (but.Name == "ImTheExitButton")
{
return;
}
}
string lsErrmsg = null;
cowSIMaintain.Validate_Supp(this, lsErrmsg);
}
Sorry forgot I left you hanging.. Hope you get this in time to be useful, It should do what you need, or at least point you in the right direction.

Related

WPF - How to not do DragDrop on MouseDoubleClick?

I've got a control with rectangles in a grid. I can drag rectangles from one cell to another within the grid. But I also need to double-click on a rectangle to bring up an edit dialog. The issue here is that just pressing the left mouse button on the rectangle will initiate a MouseMove event and cause the DragDrop to initiate when it's not wanted.
Here's the MouseMove and MouseDoubleClick event handlers:
Dim IsDragging As Boolean = False
Private Sub SchedItem_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
If IsDragging Then Exit Sub
If e.LeftButton = MouseButtonState.Pressed Then
Dispatcher.InvokeAsync(Sub()
IsDragging = True
DragDrop.DoDragDrop(Me, Me, DragDropEffects.Move)
IsDragging = False
End Sub)
End If
End Sub
Private Sub SchedItem_PreviewMouseDoubleClick(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseDoubleClick
itmEditTask_Click(Nothing, Nothing)
e.Handled = True
End Sub
I tried not initiating the MouseMove by attempting to determine the distance the mouse had traveled since the MouseLeftButtonDown event. But the x & y numbers are all over the place and I can't reliably set a threshold value. Here's that code:
Private mPos As Point
Private Sub SchedItem_MouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown
mPos = Mouse.GetPosition(Nothing)
End Sub
Private Function IsReallyMouseMove() As Boolean
Dim pPos As Point = Mouse.GetPosition(Nothing)
Debug.WriteLine(Math.Abs(mPos.X - pPos.X) & ", " & Math.Abs(mPos.Y - pPos.Y))
IsReallyMouseMove = Math.Abs(mPos.X - pPos.X) > 10 OrElse Math.Abs(mPos.Y - pPos.Y) > 10
End Function
So I'm hoping someone has done this and can provide some direction.
best way - redesign.
Make you item draggable by some object in item element. (Maybe little dot with different drag cursor)
Other area will handle double click.

Winforms TextBox - Allow numeric or 1 decimal place only

How can I prevent users from entering anything other than a numeric value or a decimal value with 1 decimal place?
The user should be allowed to enter any length of characters (if decimal value, before the decimal).
Try using Regex. This pattern should work: Regex match = new Regex(#"^[1-9]\d*(\.\d{1})?$"), put that in your validating event of the textbox. If its no match, Undo() or delete the Textbox.Text property.
Regex match = new Regex(#"^[1-9]\d*(\.\d{1})?$");
private void textBox1_Validating(object sender, CancelEventArgs e)
{
if (!match.IsMatch(textBox1.Text))
{
textBox1.Undo();
}
}
To actually undo the input immediatly, you have to use
private void textBox1_KeyUp(object sender, KeyEventArgs e)
{
if (!match.IsMatch(textBox1.Text))
{
textBox1.Undo();
}
}
Because if you use KeyDown, the TextBox has no Undo State.
2nd Edit: If you want both cases to match, you have to do the check in the Validating Event or a similar one. Since the regex uses "$" to make sure, no characters are added in the end, you cannot enter "." or else you'd end up having a number like 1. which would require additional checking.
Maybe a little late to the party on this one, but I extended a simple textbox to force the entry to always be formatted decimal.. Simple but effective
Imports System.Runtime.InteropServices
Imports System.Drawing.Imaging
Imports System.ComponentModel
Imports System.Text.RegularExpressions
<ToolboxBitmap(GetType(System.Windows.Forms.TextBox))> _
Public Class NumericTextBox
Inherits TextBox
Dim _TextBoxValue As String
Dim _CaretPosition As Integer
Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
MyBase.OnKeyDown(e)
_TextBoxValue = Me.Text
_CaretPosition = Me.SelectionStart
End Sub
Protected Overrides Sub OnKeyUp(e As KeyEventArgs)
MyBase.OnKeyUp(e)
If (Me.Text.Length = 0) Or (Me.Text = _TextBoxValue) Then Exit Sub
If IsNumeric(Me.Text) Then
If Me.Text.EndsWith(".") Then
Me.Text = Convert.ToDecimal(Me.Text) & "."
Else
Me.Text = Convert.ToDecimal(Me.Text)
End If
Else
Me.Text = _TextBoxValue
End If
Me.SelectionStart = _CaretPosition + 1
End Sub
End Class
Regex match = new Regex(#"^[1-9]\d*(.\d{1})?$");
Working Correctly

A generic utility to subscribe to SQL table changes

After a while of searching the internet, I found this piece of code that triggers upon a LINQ-based change to the Database. It trigger only once and doesn't mention or show what was changed/deleted/added, or what table was CRUDed.
static class GlobalNotifications
{
public static event OnChangeEventHandler OnChange;
public static void InitializeNotifications(string connectString)
{
// Initialize notifications
SqlDependency.Start(connectString);
// Create and register a new dependency
SqlDependency dependency = new SqlDependency();
dependency.OnChange += new OnChangeEventHandler(NotificationCallback);
System.Runtime.Remoting.Messaging.CallContext.SetData("MS.SqlDependencyCookie", dependency.Id);
}
internal static void NotificationCallback(object o, SqlNotificationEventArgs args)
{
OnChange.Invoke(o, args);
}
}
This is how I'm using it:
public partial class Nawa : Form
{
public Nawa()
{
InitializeComponent();
}
private void Nawa_Load(object sender, EventArgs e)
{
GlobalNotifications.InitializeNotifications("Server=GENISYSSERVER; Trusted_Connection=no;database=Maple_DBv1; user id=sa; password=Wc123Wc123");
GlobalNotifications.OnChange += new System.Data.SqlClient.OnChangeEventHandler(GlobalNotifications_OnChange);
}
void GlobalNotifications_OnChange(object sender, System.Data.SqlClient.SqlNotificationEventArgs e)
{
MessageBox.Show("Test");
}
private void button1_Click(object sender, EventArgs e)
{
using (DataClasses1DataContext dbcontext = new DataClasses1DataContext("Server=GENISYSSERVER; Trusted_Connection=no;database=Maple_DBv1; user id=sa; password=Wc123Wc123")) {
OrderFood random = dbcontext.OrderFoods.FirstOrDefault(id => id.ID == 10);
if (random != null) {
if (random.MenuID == 4)
random.MenuID = 1;
else
random.MenuID = 4;
dbcontext.SubmitChanges();
}
}
}
}
Can someone help in this regard? How to get more details of what was changed, type of change, Table(s) changed, and why does it fire only once. Also, how can it understand LINQ changes only? It doesn't trigger on direct changes etc.
Reference:
Extemporaneous Mumblings
A SQLDependency will only fire once, you need to recreate the dependency after it has fired.
The OnChange event fires once and then gets consumed, so you need to hook up the event again after it fires.
Dan Miser - SqlDependency
I don't have any C# code to hand to demonstrate how to deal with this but I'm sure some VB.NET should work well enough for you to come up with your own solution.
Private _permissionsDependency As SqlDependency
Private Sub doSubscribe()
_permissionsDependency = New SqlDependency(cmd.InnerCommand)
RemoveHandler _permissionsDependency.OnChange, AddressOf User_OnChange
AddHandler _permissionsDependency.OnChange, AddressOf User_OnChange
End Sub
Private Sub User_OnChange(ByVal sender As Object, ByVal e As System.Data.SqlClient.SqlNotificationEventArgs)
If _permissionsDependency IsNot Nothing Then RemoveHandler _permissionsDependency .OnChange, AddressOf User_OnChange
Select Case e.Info
Case SqlNotificationInfo.Delete
RaiseEvent UserDeleted(Me)
Case SqlNotificationInfo.Update
populateUser()
RaiseEvent UserUpdated(Me)
Case Else
End Select
End Sub
As you can see you can find out what happened by looking at e.Info, which will allow for you to know what happened (in my example I'm only looking for deletes and updates).

WPF: How do I address a usercontrol that I Instantiated at runtime?

I have added a usercontrol to my project like this:
Public Sub clickAutoDrillLeft(ByVal sender as Object, ByVal e as System.Windows.RoutedEventArgs)
Dim LSliderItem as New TriplexAmpsControl
me.LeftSlider.Items.Add(LSliderItem)
End sub
The "LSliderIn" object is an items control, and the "TriplexAmpsControl" is a usercontrol that has three writeonly properties declared as integers named "AmpsPhaseA", "AmpsPhaseB", and "AmpsPhaseC".
If I instantiate the control at runtime as above, I can immediately assign a value to one of the properties like:
Public Sub clickAutoDrillLeft(ByVal sender as Object, ByVal e as System.Windows.RoutedEventArgs)
Dim LSliderItem as New TriplexAmpsControl
me.LeftSlider.Items.Add(LSliderItem)
LSliderItem.AmpsPhaseA = 50
End sub
But only within the sub routine. I don't know how to reference the control values elsewhere in the form, because if I try to call the control by its name from some other sub, the compiler tells me, naturally, that the control is not part of the project because it has not been created yet.
All I have been able to find on the subject concerns the creation of controls in code-behind, but noting on how to connect to user controls instantiated the way I have done it.
(Pre-emptive note: excuse my VB - i'm a C# coder :)
You need to create a module level variable:
Dim _lSliderItem as TriplexAmpsControl
then in your code somewhere:
Public Sub clickAutoDrillLeft(ByVal sender as Object, ByVal e as System.Windows.RoutedEventArgs)
_lSliderItem = New TriplexAmpsControl
me.LeftSlider.Items.Add(_lSliderItem)
End sub
Or if that approach is out of the question for some reason then you can give the dynamically created control a name and later in your code use the FrameworkElement.FindName() method (most UI controls will be derived from FrameworkElement). Or you can code up your own little search function like this (excuse the C# syntax, it shouldn't be a problem for you to translate it to VB):
public static DependencyObject FindChild(this DependencyObject o, Type childType, string childName, bool checkObjectItself)
{
if (checkObjectItself && (((string)o.GetValue(FrameworkElement.NameProperty)) == childName))
return o;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
{
DependencyObject obj2 = VisualTreeHelper.GetChild(o, i).FindChild(childType, childName, true);
if (obj2 != null)
return obj2;
}
return null;
}

FindControl not finding dynamcily added user control in wizard control

I have a wizard control in wich I am adding a user control containing a simple table with
some input fields based on users entry of how many children they have. ex: how many kids do you have so I add the user control ascx based on that loop
that goes into step 5 of my wizard wich is also in a masterpage.
I then use findcontrol to atttempt the get to those input boxes so i can save the data into my db, findcontrol allway comes up null, even though the user control in visable and recreated on page load after post back.
any help greatly appreciated.
find control button:
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim numbchildren As Integer = CInt(Howmanychildren.Text)
For i As Integer = 1 To numbchildren - 1
Dim textbox As TextBox = TryCast(Me.Wizard1.FindControl("WizardStep5").FindControl("Minor_1_Child_Name"), TextBox)
'Dim textbox2 As TextBox = TryCast(Me.Wizard1.FindControl("WizardStep5").FindControl("Howmanychildren"), TextBox)
If textbox IsNot Nothing Then
Response.Write("Found TextBox1 <br>")
Dim val As String = textbox.Text
Response.Write(val & "<br>")
Else
Response.Write("not found" & "<br>")
End If
' Insert into DB
'SaveValueToDatabase(val)
Next
End Sub
user control added function on dropdown :
Protected Sub Doyouhavechildren_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Doyouhavechildren.SelectedIndexChanged
Dim numbchildren As Integer = CInt(Howmanychildren.Text)
Dim cnt As Integer = 1
'Panel1.Controls.Clear()
Select Case Doyouhavechildren.SelectedIndex
Case 0
ViewState.Add("Doyouhavechildren", numbchildren)
Do While cnt <= numbchildren
Dim uc As Web.UI.UserControl = DirectCast(Page.LoadControl("MinorChild.ascx"), Web.UI.UserControl)
uc.ID = "Minor_" + cnt.ToString()
Wizard1.ActiveStep.Controls.Add(uc)
cnt = cnt + 1
Loop
Exit Select
Case 1
Exit Select
End Select
End Sub
user control:
<%# Control Language="VB" AutoEventWireup="false" CodeFile="MinorChild.ascx.vb" Inherits="MinorChild" %>
Name
Age
SS#
DOB
the find control works in the howmanychildren field that is static
I figured it out myself
basicly, you have to referance the container, thats what everyone everywhere else where saying but I kept ignoring the answer
the correct code is
Dim textbox As TextBox = TryCast(Me.Wizard1.FindControl("WizardStep5").FindControl("Minor_1").FindControl("Child_Name"), TextBox)
you have to referance the user control name first then search within it , even though the client source is disceptive.

Resources