Validation.error event in event command - wpf

I have a text box:
<TextBox Height="20" Width="150" Text="{Binding MyProperty,NotifyOnValidationError=True,ValidatesOnDataErrors=True}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Validation.Error">
<mvvm:EventToCommand Command="{Binding MyCmd}" PassEventArgsToCommand="True" ></mvvm:EventToCommand>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
My ViewModel looks like this:
public class MyViewModel : ValidationViewModelBase, INotifyPropertyChanged
{
private int myVar;
[Range(0, 10)]
public int MyProperty
{
get { return myVar; }
set
{
myVar = value;
OnPropertyChanged("MyProperty");
}
}
public MyViewModel()
{
MyCmd = new RelayCommand<RoutedEventArgs>(Valid);
}
public RelayCommand<RoutedEventArgs> MyCmd { get; set; }
private void Valid(RoutedEventArgs args)
{
//Do something
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
#endregion INotifyPropertyChanged
}
When I catch the event Validation.Error in Code Behind it works:
But when I try to run it this way with the Event Command is not coming Valid function.
Did I miss something?

Since Validation.Error is Attached Event, then it does not work with EventToCommand normally.
The answer you will find at the link below:
EventToCommand with attached event

There is no Validation.Error event for TextBox. Furthermore, there is no Validating event for System.Controls.TextBox (which you are using).
Use LostFocus to validate the textbox or see this question if you want to use Validation with MVVM pattern

Related

PropertyChanged remains null even if the property has been changed

I am struggling with this for a while and I cannot figure it out. I have a button and a textBox. The textBox is linked to a property named: MessageDisplay. I want to be able to access this property and update the textBox in several places. Sadly, the PropertyChanged is null. The weird thing is that if I copy/paste the MessageDisplayModel class into the *MessageViewModel * class, it works ...
here is my code :
XAMLfile :
<Grid>
<Button Command="{Binding DisplayTextCommand}" Name="DisplayTextCommand" Margin="53,72,544.6,286" Width="Auto">Push</Button>
<TextBox Name="MessageDisplay" Text="{Binding MessageDisplay, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</Grid>
MessageDisplayModel file
public class MessageDisplayModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _message;
public string MessageDisplay
{
get { return _message; }
set
{
this._message = value;
this.OnPropertyChanged("MessageDisplay");
}
}
public void UpdateTextBox(string output)
{
MessageDisplay = output;
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
}//class
MessageViewModel file:
public class MessageViewModel
{
private ICommand _testCommand;
public MessageDisplayModel MessageDisplaySmt = new MessageDisplayModel();
public ICommand DisplayTextCommand
{
get
{
return new DelegateCommand(DisplayMessage);
}
set
{
if (_testCommand == value) return;
_testCommand = value;
}
}
public void DisplayMessage()
{
MessageDisplaySmt.UpdateTextBox("Successfuly downloaded");
}
}//class
MainWindow file
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MessageDisplay.DataContext = new MessageDisplayModel();
DisplayTextCommand.DataContext = new MessageViewModel();
}
}//class
I update the MessageDisplay property by using the method UpdateTextBox(string). I call this method on the click of the button. When debugging the property gets updated but when time comes to notify the UI that the property has changed, PropertyChangedEventHandler PropertyChanged has its value null ... But if I write something in the textBox, the PropertyChangedEventHandler PropertyChanged gets changed and isn't null anymore. All I want is to be able to change the textBox's property whenever I want and from anywhere I want to.
Thank you
You are using two different instances of MessageDisplayModel. You must use a shared instance.
Also the DisplayTextCommand is implemented "wrong". The set method is redundant as the property's get always returns a new instance of the ICommand.
MessageViewModel.cs
public class MessageViewModel
{
pulic MessageViewModel()
{
}
pulic MessageViewModel(MessageDisplayViewModel messageDisplayViewModel)
{
this.MessageDisplaySmt = messageDisplayViewModel;
}
public void DisplayMessage()
{
this.MessageDisplaySmt.UpdateTextBox("Successfuly downloaded");
}
public MessageDisplayViewModel MessageDisplaySmt { get; set; }
public ICommand DisplayTextCommand { get => new DelegateCommand(DisplayMessage); }
}
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Alternatively use XAML to set the DataContext (see MainWindow.xaml). Would require a parameterless constructor.
this.DataContext = new MessageViewModel(new MessageDisplayViewModel());
}
}
MainWindow.xaml
<Window>
<!--
Alternative DataContext declaration using XAML instead of C#.
Requires a parameterless constructor for both view model objects.
-->
<Window.DataContext>
<MessageViewModel>
<MessageViewModel.MessageDisplaySmt>
<MessageDisplayViewModel />
</MessageViewModel.MessageDisplaySmt>
</MessageViewModel>
</Window.DataContext>
<StackPanel>
<Button Command="{Binding DisplayTextCommand}"
Content="Push" />
<TextBox Text="{Binding MessageDisplaySmt.MessageDisplay}" />
</StackPanel>
</Window>

WPF Attach a command to a textbox on return key in NET 3.5

I am trying to attach a command and a commandparameter to a textbox on return key but without success. The parameter is the current text in the same textbox.
<TextBox x:Name="txtSearch">
<TextBox.InputBindings>
<KeyBinding Command="{Binding SearchCommand}"
CommandParameter="{Binding Path=Text, ElementName=txtSearch}" Key="Return" />
</TextBox.InputBindings>
</TextBox>
Basically I want to execute the command when user clicks on return/enter key and pass as a parameter the current text in the textbox.
I have found this link where it is said that in .NET 3.5 command parameter for keybinding is not accepting bindings. So a solution is proposed by code in code-behind but how can I pass a parameter to the command from the code?
First, you'll need to add the KeyBinding to your TextBox and set its Command on code-behind. Just add this in the constructor of your View:
public MainWindow()
{
InitializeComponent();
DataContext = new MyViewModel();
KeyBinding kb = new KeyBinding();
kb.Command = (DataContext as MyViewModel).SearchCommand;
kb.Key = Key.Enter;
txtSearch.InputBindings.Add(kb);
}
Then, you can bind the Text property of the TextBox named txtSearch to a property of your ViewModel. This way you don't need to pass a parameter as you can use the value of that property in your ViewModel inside the code that executes your Command.
Your ViewModel should look like this:
public class MyViewModel : ObservableObject
{
private string _txtSearch;
public string TxtSearch
{
get { return _txtSearch; }
set
{
if (value != _txtSearch)
{
_txtSearch = value;
OnPropertyChanged("TxtSearch");
}
}
}
private ICommand _searchCommand;
public ICommand SearchCommand
{
get
{
if (_searchCommand == null)
{
_searchCommand = new RelayCommand(p => canSearch(), p => search());
}
return _searchCommand;
}
}
private bool canSearch()
{
//implement canExecute logic.
}
private void search()
{
string text = TxtSearch; //here you'll have the string that represents the text of the TextBox txtSearch
//DoSomething
}
}
If you have access to C# 6 (Visual Studio 2015 and later versions), you can alter the call to the OnPropertyChanged to: OnPropertyChanged(nameof(TxtSearch));. This way you get rid of the "magic string" and eventual renaming of the property won't cause any problem for you.
And then your XAML should look like this: (Notice that you need to specify that te UpdateSourceTrigger must be PropertyChanged, so that your TxtSearch property of your ViewModel stays up to date when you hit the Enter key on your TextBox.
<TextBox Text="{Binding TxtSearch, UpdateSourceTrigger=PropertyChanged}" x:Name="txtSearch"/>
Your ViewModel needs to implement INotifyPropertyChanged and you need a proper ICommand implementation. Here I'll use the RelayCommand.
Those implementations are shown below.
Since your framework is .NET 3.5, implement it like this:
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
This is a implementation of the RelayCommand:
public class RelayCommand : ICommand
{
private Predicate<object> _canExecute;
private Action<object> _execute;
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
{
_canExecute = canExecute;
_execute = execute;
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}

Using eventtrigger without clicking

I have a CheckBox that's set up like so:
<CheckBox x:Name="ViewTypeCheckbox" IsChecked="{Binding ViewType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding Refresh}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
This functions as it's supposed to. When checked or unchecked by mouse click, the command is fired in the ViewModel.
You see the checkBox is databound to a bool property ("ViewType") that regularly turns from true to false and viseversa in response to user input.
The problem is I need the EventTrigger to fire when checked or unchecked by the ViewModel.
I've tried changing the "EventName" to "Checked", "IsChecked" and "UnChecked" but that doesn't seem to do anything.
Is there any additional code I need to implement? How would I get this to work?
You don't need Interaction.Triggers,
WPF provides support for commands out of the box.
Try simplifying your XAML by using a command attribute instead. It should resolve your issue.
If you need to call some code when the ViewTypeCheckbox.IsChecked changes its value, you can simply register an event handler to the PropertyChanged event of your view model (assuming it implements INotifyPropertyChanged), then call the code when the property ViewType changes:
myViewModel.PropertyChanged += new PropertyChangedEventHandler(onPropertyChanged);
...
private void onPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName=="ViewType")
{
// Do your stuff here
// Ex. fire the Refresh Command
}
}
This can be done in the ViewModel class itself or whatever you need.
To complete the example I add a short implementation of INotifyPropertyChanged in the viewmodel class:
public class MyViewModel : INotifyPropertyChanged
{
...
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler!=null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
...
// property definition to bind to ViewTypeCheckbox.IsChecked
private bool _viewType;
public bool ViewType
{
get { return _viewType; }
set
{
if (value != _viewType)
{
_viewType = value;
RaisePropertyChanged("ViewType");
}
}
}
}
Hope it helps
You don't need a trigger to execute your action. You can do it in the viewmodel when the property change.
public Boolean ViewType
{
get
{
return this.something;
}
set
{
this.something = value;
if (true == this.something)
{
this.Refresh();
}
}
}

How To Bind a Property to Textbox using MVVM and MVVM toolkit?

I am new to MVVM. to learn I created a sample application to show a message in a text box while clicking on button. In my code the button command is working properly but the property is not binding to the Textbox. How to bind Property to Textbox using MVVM?
My code is similar like given below.
View
<TextBox Name="MessageTextBox" Text="{Binding TestMessage}"/>
<Button Content="Show" Name="button1" Command="{Binding ShowCommand}">
<!-- Command Handler -->
</Button>
View Model
MyMessage myMessage;
public MainViewModel()
{
myMessage=new MyMessage();
}
//inside the ShowCommand Handler
TestMessage="Hello World";
// A Property to set TextBox Value.
Model
public class MyMessage: INotifyPropertyChanged
{
private string testMessage;
public string TestMessage
{
get { return testMessage; }
set
{
testMessage= value;
OnPropertyChanged("TestName");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
in your model you have the textMessage as being an int rather than string?
try something like this:
VIEWMODEL
private MyMessage message;
public MainViewModel()
{
message = new MyMessage();
}
public MyMessage Message
{
get { return message;}
set { message = value;}
}
//in your command:
this.Message.TestMessage = "Hello World!";
MODEL
public class MyMessage: INotifyPropertyChanged
{
private string testMessage
public string TestMessage;
{
get{ return testMessage; }
set
{
testMessage = value;
this.OnPropertyChanged("TestMessage");
}
}
//INotifyChanged Events
}
XAML
<TextBox Text="{Binding Message.TestMessage, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
I don't understand your code but I guess you should fix your binding with this:
<TextBox Name="MessageTextBox" Text="{Binding MyMessage.TestMessage}"/>
Where MyMessage should be a public property of MainViewModel

How should I move a WPF Window using MVVM?

This is probably overkill on the MVVM pattern but it's new to me and I'm interested to see if it is possible.
If I attach to the MouseMove event for a Window and do DragMove, I can move a bordeless window. Can I achieve this by some other method in MVVM or should I just accept adding this code to the Window's codebehind?
This is pure UI logic and doesn't belong in a ViewModel. The only reason you wouldn't want to put this in your code-behind would be for re-use and that is better solved with a custom Window derived control.
Personally I think any solution using MVVM would not make this code any better. Also, this is typically something that's view related and hasn't got anything to do with the data you're displaying.
IMHO, unless this is something that effects your data (aka the Model) then it is View code and should be in the View's code-behind and not in the Model.
I'm going to actually answer your question. The answer is yes. I'm using Cinch to assist me in the event binding and view model creation. The solution uses DragMove, but not as part of the code-behind (which is what I believe you are asking).
Event binding in the XAML:
<Window
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:cinchV2="clr-namespace:Cinch;assembly=Cinch.WPF"
...>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<cinchV2:EventToCommandTrigger Command="{Binding MouseLeftButtonDown}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
...
</Grid>
</Window>
In the ViewModel:
[ExportViewModel("MainViewModel")]
[PartCreationPolicy(CreationPolicy.NonShared)]
internal sealed class MainViewModel : ViewModelBase
{
public SimpleCommand<object, EventToCommandArgs> MouseLeftButtonDown { get; private set; }
[ImportingConstructor]
public MainViewModel(IUIVisualizerService uiVisualizerService)
{
...
MouseLeftButtonDown = new SimpleCommand<object, EventToCommandArgs>(OnMouseLeftButtonDown);
}
private static void OnMouseLeftButtonDown(EventToCommandArgs e)
{
((Window)e.Sender).DragMove();
}
}
Fairly simple, right? Any events that come from the UI contain the View as the sender. So, here, we simply call the method on the view within the event handler in the ViewModel.
The project I'm working on uses no code-behind (even if it is not recommended in MVVM).
I know that I am a little late to the question, but this is what I have been using for sometime now and it works like a charm.
DashboardViewModel viewModel;
public DashboardView()
{
InitializeComponent();
viewModel = new DashboardViewModel();
viewModel.RequestClose += (s, e) => Application.Current.Dispatcher.Invoke(this.Close);
viewModel.RequestMinimize += (s, e) => Application.Current.Dispatcher.Invoke(() => { this.WindowState = WindowState.Minimized; });
DataContext = viewModel;
}
and something like this in your viewModel
#region Public Event Handlers
public event EventHandler<EventArgs> RequestClose;
public event EventHandler<EventArgs> RequestMinimize;
#endregion
Using the ICommand interface...
#region ICommand Members
public ICommand CloseCommand { get; private set; }
public ICommand MinimizeCommand { get; private set; }
#endregion
Configure the commands...
private void SetupCommands()
{
CloseCommand = new RelayCommand(CloseApplication);
MinimizeCommand = new RelayCommand(MinimizeApplication);
}
Here is the RelayCommand class.
public class RelayCommand : ICommand
{
#region Private Readonly Properties
private readonly Action<object> executeCommand;
private readonly Predicate<object> canExecute;
#endregion
#region Constructors
public RelayCommand(Action<object> execute) : this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
this.executeCommand = execute;
this.canExecute = canExecute;
}
#endregion
#region Public ICommand Members
public bool CanExecute(object parameter)
{
return canExecute == null ? true : canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
executeCommand(parameter);
}
#endregion
}
And some example methods...
private void MinimizeApplication(object obj)
{
RequestMinimize(this, new EventArgs());
}
private void CloseApplication(object obj)
{
RequestClose(this, new EventArgs());
}
Hope this helps!
I know it's an old question. However I prepared another simple implementation. Use following behavior to make window moveable:
public class WindowMoveBehavior : Behavior<Grid>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
}
protected override void OnDetaching()
{
AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;
base.OnDetaching();
}
private void AssociatedObject_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
Window.GetWindow(AssociatedObject).DragMove();
}
}
Xaml example:
<Style x:Key="CustomWindowStyle" TargetType="{x:Type Window}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Grid>
<i:Interaction.Behaviors>
<behaviors:WindowMoveBehavior/>
</i:Interaction.Behaviors>
<!-- different controls and content -->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
11 years passed, but maybe someone is still interested in case to drag window using MVVM. This tricky solution is based on window's property "Tag" - almost no one use it but it's time to find out it's strength :) So all you need is System.Windows.Interactivity nuget, no Cinch or events!
Xaml:
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<Window ... Tag="{Binding WindowTag}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding DragMoveWindowCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
Let's find out your current window and move it. In ViewModel:
private object _windowTag;
public object WindowTag
{
get
{
return _windowTag;
}
set
{
_windowTag = value;
OnPropertyChanged("WindowTag");
}
}
private RelayCommand _dragMoveWindowCommand;
public RelayCommand DragMoveWindowCommand
{
get
{
return _dragMoveWindowCommand ??
(_dragMoveWindowCommand = new RelayCommand(obj =>
{
try
{
var window = WindowService.GetCurrentWindowByTag(WindowTag = 1);
window.DragMove();
}
catch (Exception ex)
{
}
}));
}
}
public static Window GetCurrentWindowByTag(object tag)
{
return (from Window w in App.Current.Windows
where w.Tag == tag
select w)?.FirstOrDefault();
}
Enjoy!)

Resources