Raise event if any control has been changed WPF - c#

I want make validation in my WPF application. And the approach I want to use is I want to take custom action if any value of my controls has been changed.
How I can do that suppose I have control like this
<TextBox x:Name="TextBox1" Text="{Binding Path=Box1,UpdateSourceTrigger=PropertyChanged}" />
<TextBox x:Name="TextBox2" Text="{Binding Path=Box2,UpdateSourceTrigger=PropertyChanged}" />
And If user change the value one of that control I want to create custom action for example (For my thinking )
private void Window_Controls_Property_Changed(object sender,RoutedEventArgs e){
if(((Control)sender)=="TextBox1")
MessageBox.Show("Show message here of validation some control","Attention",MessageBoxButton.OK);
}
I'm still confusing combine the INotifyPropertyChanged or ValidationRule with displaying error what I want with MessageBox. I'm still newbie using this kind of features.
I have read many articles about INotifyPropertyChanged or ValidationRule but I'm still don't know how to get the custom action like I said before. And the custom validation may use another textbpx value to validate with the other textbox.
Any helps?..

You can register the handler on the Container that hosts your TextBox's. Like this:
<StackPanel TextBox.LostFocus="TextBox_OnLostFocus">
<TextBox x:Name="TextBox1" Text="{Binding Path=Box1,UpdateSourceTrigger=PropertyChanged}" />
<TextBox x:Name="TextBox2" Text="{Binding Path=Box2,UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
This way the same handler will be used for all TextBox's and you can query e.Source to find out which TextBox triggered the event.

for Validation in mvvm you can take IDataErrorInfo. there are examples all over the net.
and if you really whant to do some special action when a property in your viewmodel change, you can simply subscribe to your own viewmodel PropertyChanged event and handle your stuff

You may want to read this block post about BindingGroups and validation (and this related blog post). They show you how you can validate multiple controls at once using custom validation rules.

<TextBox HorizontalAlignment="Left" LostFocus="OnLostFocus"/>
Here's an easy way. Validate using the LostFocus Event in WPF
private void TextBox_LostFocus_1(object sender, RoutedEventArgs e) {
var thisTextBox = (TextBox)sender;
if (thisTextBox.Text == "") {
MessageBox.Show("Validate!");
}
}

Related

How to set and get tag in xaml dynamically?

While creating GUI using xaml, I created a textbox with a tag like this:
<TextBox Name="TextBox" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="216,178,143,120" Width="158"
Tag="myTag"/>
Now I want to let the user be able to change this tag. For that, I am looking for a kind of function of form:
TextBox.SetTag( "User Provided Tag" )
So that the tag can be changed into this one:
<TextBox Name="TextBox" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="216,178,143,120" Width="158"
Tag="User Provided Tag"/>
After searching the internet for quite a while, I didn't come up with any practical solution. Could someone help? Thanks.
You can use a binding between two controls. Say a user is allowed to enter a tag value from a TextBox. You just bind the Tag of the second TextBox to a Text property of the first TextBox:
<TextBox Name="enterTagTextBox" />
<TextBox Name="getTagTextBox" Tag="{Binding ElementName=enterTagTextBox, Path=Text}"/>
To test it I added a Button in my XAML:
<Button Height="25" Click="Button_Click_1"/>
In code behind I just retrieve the tag value and display it like this:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
string text = this.getTagTextBox.Tag.ToString();
global::System.Windows.Forms.MessageBox.Show(text);
}
I think your problem may arise from you naming your TextBox, "TextBox". Try giving it a name that does not clash with the class name, like "txtMyTextBox".
Then you can do, txtMyTextBox.Tag = "User Provided Tag";.
Or you can bind to it as PiotrWolkowski suggests.
However, I would like to add, that it seems like there should be a cleaner way of achieving your desired behaviour. With the caveat that I don't know the details of what you are trying to implement.
I strongly suggest creating a ViewModel (see: MVVM Pattern) to hold the data you want users to be able to edit. Then use the bindings in WPF to display the data.
You would need to use the property element usage in order to set the Tag property in Extensible Application Markup Language (XAML) to anything other than an object with a known and built-in type converter, such as a string.

Listen for generic events

I have a function I would like to run on after update of a lot of different text boxes, is it possible to listen for a generic after update event rather than the specific events?
So rather than 100 individual calls to the function, just one listener?
Edit: It would appear we are using a combination of MVVM and traditional code behind.
Here is one of the textboxes:
<TextBox Text="{Binding APhaseFrom}" x:Name="txtFromWhereA" TabIndex="26" HorizontalContentAlignment="Center" HorizontalAlignment="Left" Height="48" TextWrapping="NoWrap" VerticalAlignment="Top" Width="261" FontSize="26" FontWeight="Bold" BorderBrush="Black" BorderThickness="1" Margin="289,656,0,0" GotMouseCapture="txtFromWhereA_GotMouseCapture" GotFocus="txtFromWhereA_GotFocus" Grid.Row="3" />
The code from the view Model:
public string APhaseFrom
{
get { return new string((char[])_f.Rows[1].GetValue("Alpha09")); }
set
{
if (value.Length <= 35)
{
_f.Rows[1].SetValue("Alpha09", value);
}
else
{
MessageBox.Show("Error: String length Longer than 35 Characters.");
}
}
}
We also are using some commands for other processes:
public ICommand Updatesql
{
get;
internal set;
}
private void CreateUpdatesql()
{
Updatesql = new RelayCommand(UpdatesqlExecute);
}
private void UpdatesqlExecute()
{
_f.Update();
}
Should I be using commands or just link the events to functions in the viewmodel?
Since you are using WPF, and if I understand your problem correctly, then the RoutedEvents that WPF uses may help you here. Essentially, events like the LostFocus event of a TextBox will bubble up your UI hierarchy and can be handled by a common parent control. Consider this snippet of XAML and codebehind:
<StackPanel TextBox.LostFocus="TextBoxLostFocus">
<TextBox></TextBox>
<TextBox></TextBox>
<TextBox></TextBox>
</StackPanel>
Codebehind:
private void TextBoxLostFocus(object sender, RoutedEventArgs e)
{
MessageBox.Show("Lost Focus!");
}
You will find that the event handler is called for any of the three textboxes when focus is lost. The sender parameter or e.Source can be used to find the textbox that fired the event.
This pattern holds true for any RoutedEvent, so things like Button.Click or TextBox.TextChanged and many more can be caught in this manner.
Really and truthfully you should be using a single design pattern... ie MVVM when writing WPF applications, each textbox would be bound to a property which implements the INotifyPropertyChange interface.
In the setter of each property you would essentially update the value, fire a property changed event and then either make a call to your method or simply add an event handler on the view model for the PropertyChanged event.
Also... MessageBox.Show is a bad idea in your view models, its hard to unit test it.
Update
I removed my previous ideas because I now understand more clearly what you are looking for.
But you definitely need to use the LostFocus event.
<TextBox Text="{Binding APhaseFrom}" x:Name="txtFromWhereA" LostFocus="OnLostFocus" />

WP8 Databind button click/Command with RoutedEventHandler

Fairly new to Windows Phone and Xaml and I decided to start using the DataTemplates as it looked neater and I could easily switch them etc.
I have a requirement where on a button click depending on the data on the item in the list I want to call a different function or with different parameters. I thought the easiest way would be to bind a RoutedEventHandler to it via an anonymous function.
When I did this in code-behind with static controls on the formed it worked perfectly. It also worked when I added my own controls to a stack panel etc. But it was all quite messy.
// Example of RoutedEventHandler that works when I create the button in code behind
model.clickEventHandler = (s, e) => LoadResult(r.id);
<ScrollViewer Name="scrvResults" >
<ListBox Name="lbResults" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Command="{Binding clickEventHandler}" >
// Stuff
// Doesn't crash but doesn't fire the event
</Button>
<Button Click="{Binding clickEventHandler}" >
// Stuff
// Throws a com exception
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
I've tried various sub options. All the examples i've seen seem to link to a static function. Is this just some syntax i'm getting wrong is can I not bind to it this way?
You need to bind your command to a type of ICommand. See here for more info:
ICommand interface
Command Binding
Button click event can be bound by using interaction triggers, not by simply binding the event to the click attribute:
Using EventTrigger in XAML for MVVM – No Code Behind Code

WPF Check box: Check changed handling

In WPF data binding, I can bind the IsChecked property to some data, e.g. user setting, but I need to handle "CheckChanged" event, I know I can seperately handle Checked, Unchecked event, but is there any way to get notified when this value is changed?
<CheckBox Content="Case Sensitive" IsChecked="{Binding bSearchCaseSensitive,
Source={x:Static Properties:Settings.Default}}" />
Note: I don't care if it is checked or unchecked. I just want to be notified when it is changed.
That you can handle the checked and unchecked events seperately doesn't mean you have to. If you don't want to follow the MVVM pattern you can simply attach the same handler to both events and you have your change signal:
<CheckBox Checked="CheckBoxChanged" Unchecked="CheckBoxChanged"/>
and in Code-behind;
private void CheckBoxChanged(object sender, RoutedEventArgs e)
{
MessageBox.Show("Eureka, it changed!");
}
Please note that WPF strongly encourages the MVVM pattern utilizing INotifyPropertyChanged and/or DependencyProperties for a reason. This is something that works, not something I would like to encourage as good programming habit.
As a checkbox click = a checkbox change the following will also work:
<CheckBox Click="CheckBox_Click" />
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
// ... do some stuff
}
It has the additional advantage of working when IsThreeState="True" whereas just handling Checked and Unchecked does not.
Im putting this in an answer because it's too long for a comment:
If you need the VM to be aware when the CheckBox is changed, you should really bind the CheckBox to the VM, and not a static value:
public class ViewModel
{
private bool _caseSensitive;
public bool CaseSensitive
{
get { return _caseSensitive; }
set
{
_caseSensitive = value;
NotifyPropertyChange(() => CaseSensitive);
Settings.Default.bSearchCaseSensitive = value;
}
}
}
XAML:
<CheckBox Content="Case Sensitive" IsChecked="{Binding CaseSensitive}"/>
I know this is an old question, but how about just binding to Command if using MVVM?
ex:
<CheckBox Content="Case Sensitive" Command="{Binding bSearchCaseSensitive}"/>
For me it triggers on both Check and Uncheck.
A simple and proper way I've found to Handle Checked/Unchecked events using MVVM pattern is the Following, with Caliburn.Micro :
<CheckBox IsChecked="{Binding IsCheckedBooleanProperty}" Content="{DynamicResource DisplayContent}" cal:Message.Attach="[Event Checked] = [Action CheckBoxClicked()]; [Event Unchecked] = [Action CheckBoxClicked()]" />
And implement a Method CheckBoxClicked() in the ViewModel, to do stuff you want.
What about the Checked event? Combine that with AttachedCommandBehaviors or something similar, and a DelegateCommand to get a function fired in your viewmodel everytime that event is called.

Access XAML controls from C# code-behind

I have two files in my VS project: Custom.xaml and Custom.cs
In my XAML file, I have the following text boxes:
<TextBox x:Name="TextBox1" Text="{Binding Value, Mode=TwoWay}" Foreground="Black" Background="Green" SelectionChanged="TextBox1_SelectionChanged" />
<TextBox x:Name="TextBox2" Text="{Binding Value, Mode=TwoWay}" Foreground="Black" Background="Green" SelectionChanged="TextBox2_SelectionChanged" />
In my .cs, I have the following method:
void TextBox1_SelectionChanged(object sender, RoutedEventArgs e)
{
TextBox t = e.Source as TextBox
}
I can successfully hit the event handler above. Then, I can grab TextBox1 and it's properties by using e.Source, but I would like to access TextBox2 and it's properties.
As a sidenote, the .cs file is just a C# class that I am referencing, not a xaml.cs. Additionally, I understand that I could implement this via a UserControl, but cannot do that in this scenario for reasons that are outside the scope of this post.
Please advise on how I can get/set properties of TextBox2.
Thanks.
EDIT: Any other input on this? As a workaround, I've added an event handler called TextBox2_Loaded, and then set e.Source to an instance variable. Then, in TextBox1_SelectionChanged, I can access the instance variable. Would really like to just target the control directly (ex. TextBox2.IsEnabled). I must be missing a declaration or inheritance somewhere. Can't even find the control using FindName.
Alright, so I apparently had left out a critical component in this post... My TextBox controls are inside of DataTemplate controls. From my research, the TextBox controls cannot be accessed when inside of DataTemplate controls. I really didn't think that would matter, but I guess the instance variables are not created when this scenario exists.
If I've interpreted this incorrectly, please provide input. For now, I've gone ahead and added a Loaded event and defined my TextBox controls as instance variables so that I can access them and change properties when other activities occur.
Thanks for everyone's input.
As long as you have set a namein the XAML, you can access it directly by name (The XAML compiler will create an instance variable for you.)
void TextBox1_SelectionChanged(object sender, RoutedEventArgs e)
{
TextBox t = e.Source as TextBox
TextBox2.Text = "Whatever";
}
This just happened to me. I had to close my solution and reopen it.

Categories

Resources