MVVM Model-property not set when command is executed from code-behind - c#

I execute a command on my ViewModel from a TextBox-KeyUp event. The problem I'm facing is that text from the TextBox which binds to a property on the ViewModel, is (still) null when the command is executed.
ViewModel:
private string _myText;
public string MyText
{
get { return _myText; }
set
{
_myText = value;
RaisePropertyChanged("MyText");
}
}
// ... ICommand stuff here
private object HandleMyCommand(object param)
{
Console.WriteLine(MyText); // at this point MyText --> 'old' value, e.g. null
return null;
}}
XAML:
<StackPannel>
<TextBox x:Name="tbTest" KeyUp="TextBox_KeyUp" Text="{Binding MyText, Mode=TwoWay}" />
<Button x:Name="btnTest" Content="Click" Command="{Binding MyCommand}" />
</StackPannel>
Code behind:
private void TextBox_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
if (btnTest.Command.CanExecute(null))
{
btnTest.Command.Execute(null);
}
}
}
The binding and command both work. When executing the command the normal way, using the button, the property is set nicely.
Am I not doing this correctly?

Set UpdateSourceTrigger=PropertyChanged as by default MyText will be updated on lost focus:
Text="{Binding MyText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
also, not related to your problem, but you can create InputBinding for TextBox to execute some Command when Enter is pressed:
<TextBox x:Name="tbTest" Text="{Binding MyText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding MyCommand}"/>
</TextBox.InputBindings>
</TextBox>

Try to change the binding of the text property to:
Text="{Binding MyText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"

Related

WPF CheckBox Command inside a Listview DataTemplate

My CheckBox Command does not work. I want to pass the SelectedItem of the ListView to the Command when the SelectedItem is checked or unchecked, but the Command does not execute at all. I also suspect my CommandParameter is not configured correctly?
I am pretty sure the problem is because the CheckBox is within a ListView DataTemplate.
Can someone show me how to set this up? I tried to follow examples I found, but nothing seems to work. thanks.
XAML
<ListView x:Name="lvReferralSource" ItemsSource="{Binding ReferralSourceTypeObsCollection}" Style="{StaticResource TypeListViewStyle}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<CheckBox x:Name="ckbReferralIsChecked" Content="{Binding Value}" IsChecked="{Binding Active}" Style="{StaticResource CheckBoxStyleBase2}"
Command="{Binding CheckBoxIsChecked}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=SelectedItem}">
</CheckBox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
CODE
private ICommand _CheckBoxIsChecked;
public ICommand CheckBoxIsChecked
{
get
{
if (_CheckBoxIsChecked == null)
{
_CheckBoxIsChecked = new RelayCommand<object>(ExecuteCheckBoxIsChecked, CanExecuteCheckBoxIsChecked);
}
return _CheckBoxIsChecked;
}
}
public bool CanExecuteCheckBoxIsChecked(object parameter)
{
return true;
}
public void ExecuteCheckBoxIsChecked(object parameter)
{
Mouse.OverrideCursor = Cursors.Wait;
if (parameter != null)
{
//Do Stuff...
}
Mouse.OverrideCursor = Cursors.Hand;
}
Your command should get executed provided that the CheckBoxIsChecked property belongs to the data object where the Value and Active properties are defined.
If it belongs to the view model, you could bind to it using a RelativeSource:
<CheckBox x:Name="ckbReferralIsChecked" Content="{Binding Value}" IsChecked="{Binding Active}"
Style="{StaticResource CheckBoxStyleBase2}"
Command="{Binding DataContext.CheckBoxIsChecked, RelativeSource={RelativeSource AncestorType=ListView}}"
CommandParameter="{Binding}">

Hide button inside the ListView

I have got a ListView and each row has a Button. I want to hide Buttons until the user selects any row.
I used in my ViewModel :
private Visibility _deleteButtonVisibility;
public Visibility DeleteButtonVisibility { get { return _deleteButtonVisibility; } set { _deleteButtonVisibility = value; OnPropertyChanged(nameof(DeleteButtonVisibility)); } }
In my Constructor
DeleteBtnVisibility = Visibility.Hidden;
XAML code i used this
<GridViewColumn Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate >
<StackPanel HorizontalAlignment="Center">
<Button Click="DeleteBand_Click" Visibility="{Binding DeleteBtnVisibility }" Content="Delete" Width="88"></Button>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Delete" >Delete</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
ViewModel event listener:
private void WarningModel_OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == nameof(SelectedWarning))
{
if(SelectedWarning != null)
{
DeleteBtnVisibility = Visibility.Visible;
}
}
}
binding is not working inside the ListView.
If i use the same binding any other objects outside of the ListView, it hides the object.
I tried to hide <StackPanel> which contains the Button but still no success.
I am not sure why Binding doesn't work
If the DeleteBtnVisibility property is defined in the view model of the ListView (or its parent view), you could bind to it using a RelativeSource:
<Button Click="DeleteBand_Click"
Visibility="{Binding DataContext.DeleteBtnVisibility, RelativeSource={RelativeSource AncestorType=ListView}}"
Content="Delete" Width="88" />

Binding was not executed in CommandBinding

i have this xaml code:
<Window.CommandBindings>
<CommandBinding Command="WpfApplication1:MainCommands.Search" Executed="Search"/>
</Window.CommandBindings><Grid>
<StackPanel>
<ListView ItemsSource="{Binding SearchContext}" />
<TextBox Text="{Binding LastName}">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{x:Static WpfApplication1:MainCommands.Search}" />
</TextBox.InputBindings>
</TextBox>
</StackPanel>
The Search-Method looks like:
private void Search(object sender, RoutedEventArgs e)
{
SearchContext = new ObservableCollection<string>(list.Where(element => element.Name == LastName).Select(el => el.Name).ToList());
}
MainCommands:
public static class MainCommands
{
public static RoutedCommand Search = new RoutedCommand();
}
But if i press enter while focus is in textbox, the binding isĀ“nt computet and LastName is Null. What is the reason? How can I avoid this? Or is it possible to explicit call the binding operation?
Thank you in advance.
Set the UpdateSourceTrigger property to PropertyChanged:
<TextBox Text="{Binding LastName, UpdateSourceTrigger=PropertyChanged}">
This will cause the source property (LastName) to be set immediately: https://msdn.microsoft.com/en-us/library/system.windows.data.updatesourcetrigger(v=vs.110).aspx
As I can see your Window is a view-model for it. I recommend you to use MVVM and have separate class for view-model where you can place desired ICommand and use CommandParameter on KeyBinding:
<TextBox x:Name="searchBox"
Text="{Binding LastName}">
<TextBox.InputBindings>
<KeyBinding Key="Enter"
Command="{Binding Path=SearchCommand}"
CommandParameter="{Binding Path=Text, ElementName=searchBox}" />
</TextBox.InputBindings>
</TextBox>

How to handle the TextBlock Click within the Grid Control in WPF using prism 6?

I am having an scenario where I show a window to the user and ask them to choose anything by left click on it. See attached pix
So in this Window I have corresponding WindowViewModel following a Prism 6.1.0 framework. I want to bind this click event to the Grid instead of Binding with the each TextBlock each. Is it possible?
if yes, I tried this. In the grid Control my code is this.
<Grid x:Name="Locals1">
<Grid.InputBindings>
<MouseBinding MouseAction="LeftClick"
Gesture="LeftClick" Command="{Binding MouseCommand,
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
CommandParameter="{Binding ElementName=Locals1,
Path=SelectedItem, Mode=TwoWay}"
/>
</Grid.InputBindings>
<TextBlock Focusable="True" text="textblock1" />
<TextBlock Focusable="True" text="textblock2" />
<TextBlock Focusable="True" text="textblock3" />
<TextBlock Focusable="True" text="textblock4" />
</Grid>
And in the WindowViewModel I have a code like this.
public WindowViewModel(IEventAggregator eventAggregator)
{
MouseCommand = new DelegateCommand<string>(OnConnection);
}
private void OnConnection(string obj)
{
...
}
But I don't get the TextBlock.Text value in that OnConnection method. Is it really so tough? What I know about WPF and MVVM that we can handle the child click event in the parent control itself. This will reduce duplicate codes.
I know I am doing something definitely wrong. But I don't know what exactly. How can I pass this value from WindowViewModel to the MainWindowViewModel?
I can achieve the same functionality using a binding each in all the textblocks but that will not serve the purpose of Prism. basically all the text Block click events functionality is same only the value of the textblock will be different.
thanks
Honestly, i don't like my answer, but:
You use Grid, not DataGrid and similar, so what is SelectedItem in you context?!
I cant invent how to use pretty binding in this case, so i changed command
public DelegateCommand<Object> MouseCommand { get; set; }
public WindowViewModel(IEventAggregator eventAggregator)
{
MouseCommand = new DelegateCommand<object>(OnConnection);
}
and
private void OnConnection(object obj)
{
var text = GetTextFromClickOnGrid(obj);
}
private string GetTextFromClickOnGrid(object obj)
{
var grid = obj as Grid;
if (grid != null)
{
var mousePos = Mouse.GetPosition(grid);
var itemUnderMouse = VisualTreeHelper.HitTest(grid, mousePos);
var textBlock = itemUnderMouse.VisualHit as TextBlock;
if (textBlock != null)
{
return textBlock.Text;
}
}
var textBlockUnderMouse = Mouse.DirectlyOver as TextBlock;
if (textBlockUnderMouse != null)
{
return textBlockUnderMouse.Text;
}
return string.Empty;
}
and xaml
<Grid Grid.Row="1" x:Name="Locals1">
<Grid.InputBindings>
<MouseBinding MouseAction="LeftClick"
Gesture="LeftClick"
Command="{Binding MouseCommand,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
CommandParameter="{Binding ElementName=Locals1}"
/>
</Grid.InputBindings>
<TextBlock Focusable="True" Text="textblock1" Height="30" Width="100" Margin="115,45,302,84" />
<TextBlock Focusable="True" Text="textblock2" Height="30" Width="100" Margin="115,10,302,119"/>
<TextBlock Focusable="True" Text="textblock3" Height="30" Width="100" Margin="10,45,407,84"/>
<TextBlock Focusable="True" Text="textblock4" Height="30" Width="100" Margin="10,10,407,119"/>
</Grid>
i think you looking this:
<i:Interaction.Triggers>
<i:EventTrigger EventName="LeftClick">
<command:EventToCommand
Command="{Binding Main.MouseCommand ,
Mode=OneWay,
Source={StaticResource Locator}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
binding what you want. Any event to almost any command.
ViewModelLocator:
public class ViewModelLocator
{
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
}
/// <summary>
/// Gets the Main property.
/// </summary>
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
}

TextBox KeyDown Trigger Event not working for Backspace and Delete key

I have a Textbox and for that textbox I have attached a keydown event. Everything is working fine but I just noticed that when i'm pressing the 'Backspace' and 'Delete' Key, the binding command is not being called.
My View xaml file :-
<TextBox x:Name="textBox" Width="500" Text="{Binding TextBoxText, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown">
<cmd:EventToCommand Command="{BindingPath=TextBoxKeyDownEvent}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
My ViewModel cs file :-
//TextBox Key Down Event Handler
private DelegateCommand _textBoxKeyDownEvent;
public ICommand TextBoxKeyDownEvent
{
get
{
if (_textBoxKeyDownEvent == null)
{
_textBoxKeyDownEvent = new DelegateCommand(TextBoxKeyDownEventHandler);
}
return _textBoxKeyDownEvent;
}
set { }
}
Can somebody give me some suggestion
EDIT:
You have to use PreviewKeyDown the it works. KeyDown is not fired on Space and Delete. If you ignore MVVM and put the handler of KeyDown in codebehind it will also fail.
How about binding the Text-Property to a string in you viewmodel?
I build a fast, simple example of my idea.
Result
Text from the TextBox on the left side is simply populated to the Textblock on the right side.
View
<Window x:Class="WpfApplication1.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">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding TextBoxValue, UpdateSourceTrigger=PropertyChanged}" Width="250"/>
<StackPanel Orientation="Horizontal">
<TextBlock>"</TextBlock>
<TextBlock Text="{Binding TextBoxValue, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock>"</TextBlock>
</StackPanel>
</StackPanel>
</Window>
ViewModel
public class MainWindowViewModel : INotifyPropertyChanged
{
private string textBoxValue;
public string TextBoxValue
{
get { return textBoxValue; }
set
{
textBoxValue = value;
OnTextBoxValueChanged();
RaisePropertyChanged();
}
}
void OnTextBoxValueChanged()
{
// you logic here, if needed.
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
you most use PreviewKeyDown event.
Like this:
<EventSetter Event="PreviewKeyDown" Handler="TextBox_PreviewKeyDown"/>
Edit: You are correct - the default behavior is not executed. You should use ec8ors solution, which is much better anyway:
<TextBox x:Name="textBox" Width="500" Text="{Binding TextBoxText, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewKeyDown">
<i:InvokeCommandAction Command="{Binding TextBoxKeyDownEvent, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
Original:
You can use InputBindings to call your command when "special" keys have been pressed:
<TextBox x:Name="textBox" Width="500" Text="{Binding TextBoxText, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown">
<cmd:EventToCommand Command="{BindingPath=TextBoxKeyDownEvent}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBox.InputBindings>
<KeyBinding Command="{Binding TextBoxKeyDownEvent}" Key="Delete" />
<KeyBinding Command="{Binding TextBoxKeyDownEvent}" Key="Back" />
</TextBox.InputBindings>
</TextBox>

Categories

Resources