I have the following code:
<Button Focusable="True">
<Button.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{Binding ButtonClickedCommand}" />
<MouseBinding Gesture="CTRL+LeftClick" Command="{Binding ButtonClickedWithCtrlCommand}" />
</Button.InputBindings>
</Button>
the view model is like this
public ICommand ButtonClickedCommand { get; }
public ICommand ButtonClickedWithCtrlCommand { get; }
...
{
ButtonClickedCommand = new DelegateCommand(() => { });
ButtonClickedWithCtrlCommand = new DelegateCommand(() => { });
}
Now if I click the button, the command is correctly executed. But somehow the focus of the button does not get set. Can someone tell me why?
It seems that the Command prevents the base functionality of the click (like the button down visalization as well). Is there a way to invoke that when using InputBindings?
PS: I know that I can achieve the same with behaviors and "event to command binding" (in fact that's how I fixed it). Maybe I'm abusing the input binding and I should not use it in the first place for "things" which are already bound (like click etc.)?
Related
In my MVVM Application i have the MainWindow which displays my child view in a ContentControl Element.
The MainWindow DataContext houses an ICommand which allows the child views to change the view:
public ICommand ChangePageCommand { get; }
private void ChangePage(object parameter)
{
Type paramType = parameter as Type;
if (paramType == typeof(Main))
{
ViewModel = new Main();
}
}
The ICommand works great when im Calling it from the childs wpf like this:
<Button
Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType {x:Type Window}}, Mode=OneWay}"
CommandParameter="{x:Type ViewModel:Main}">
Connect to Process
</Button>
But now i want to call the ICommand from the ViewModel of the childview, because after clicking the button i need to execute some code and dependent on the result i want to ether change the window or display an error message.
I have tried a lot of searching on how to do this, but I could not find anything about calling an ICommand of an Ancerstor from code.
Maybe I'm looking at wrong and there is a different way to achieve what I want?
I'm trying to get the four arrow keys to be bound to a command in my ViewModel, but they are not working. I have a ContentControl in a Window with InputBindings like so:
<ContentControl.InputBindings>
<KeyBinding Command="{Binding EndCmd}" Key="Esc" />
<KeyBinding Command="{Binding PanUpCmd}" Key="Up" />
<KeyBinding Command="{Binding PanDownCmd}" Key="Down" />
<KeyBinding Command="{Binding PanLeftCmd}" Key="Left" />
<KeyBinding Command="{Binding PanRightCmd}" Key="Right" />
</ContentControl.InputBindings>
In my ViewModel:
public RelayCommand EndCmd { get; set; }
public RelayCommand PanUpCmd { get; set; }
public RelayCommand PanDownCmd { get; set; }
public RelayCommand PanLeftCmd { get; set; }
public RelayCommand PanRightCmd { get; set; }
public MainViewModel()
{
EndCmd = new RelayCommand(End);
PanUpCmd = new RelayCommand(PanUp);
PanDownCmd = new RelayCommand(PanDown);
PanLeftCmd = new RelayCommand(PanLeft);
PanRightCmd = new RelayCommand(PanRight);
}
//functions that the commands call here
Now, the Escape key works fine, but the four arrow keys do not. Why is this? They are set up exactly the same. I thought maybe it was something to do with the DataContext so I put the KeyBindings in the WindowsInputBindings` but it was the same issue.
Edit: I've tested every key on my keyboard. Every key fires properly except the four arrow keys. I checked if the Content of the ContentControl was swallowing the events, and it was not. In fact, the Control that is the Content has it's own keydown event, which is also never called, nor is the previewkeydown, with the arrow keys.
I copied your code and it seems to work fine.
The only reason I can think for this not to work in your case (especially if Esc works, but not the other keys) is that whatever content you're using inside of the ContentControl also contains input bindings for the direction keys.
In this case, the bindings in the content would override the bindings you've set for the ContentControl itself.
Arrow keys are handled by KeyboardNavigation default.
You should disable KeyboardNavigation and make sure control focusable.
<Grid Background="{Binding Background}" KeyboardNavigation.ControlTabNavigation="None" Focusable="True">
<Grid.InputBindings>
<KeyBinding Key="Left" Command="local:OpsCommands.MoveLeft" />
<KeyBinding Key="Up" Command="local:OpsCommands.MoveUp" />
<KeyBinding Key="Right" Command="local:OpsCommands.MoveRight" />
<KeyBinding Key="Down" Command="local:OpsCommands.MoveDown" />
</Grid.InputBindings>
</Grid>
public ICommand PanRightCmd
{
get { return (ICommand)GetValue(SearchBarEnterCmdProperty); }
set { SetValue(SearchBarEnterCmdProperty, value); }
}
...
PanRightCmd= new RelayCommand(o => PanRightCmdExecute());
https://www.c-sharpcorner.com/UploadFile/20c06b/icommand-and-relaycommand-in-wpf/
I am quiet new to programming and am currently learning C# and the MVVMC pattern (which is I think basically the same as MVVM pattern).
I need to code a database tool for ChiliPlants for university. There you should be able to edit an existing item from an ObservableCollection.
This ObservableCollection I displayed in a DataGrid, see this:DataGrid
Below the DataGrid there are three buttons: Add, Edit and Delete.
I was able to programm the AddButton, aswell as the DeleteButton.
Unfortunately I don't know how to programm the EditButton.
It should open a new window, where the SelectedItem should be opened like this:EditWindow
Until now my EditButton does the same thing as my AddButton.
See my code here:
View:
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button Content="Add" Margin="5,5,0,5" Width="100" Command="{Binding AddCommand}" />
<Button Content="Edit" Margin="5,5,0,5" Width="100" Command="{Binding EditCommand}" />
<Button Content="Delete" Margin="5,5,540,5" Width="100" Command="{Binding DeleteCommand}" />
<Button Content="Sichern" Margin="5,5,5,5" Width="100" Command="{Binding SaveCommand}" />
</StackPanel>
ViewModel:
private ICommand _editCommand;
public ICommand EditCommand
{
get { return _editCommand; }
set { _editCommand = value; }
}
Controller:
public void SDInitialize()
{
var view = new WindowStammdatenverwaltung();
mViewModel = new WindowStammdatenverwaltungViewModel
{
EditCommand = new RelayCommand(EditCommandExecute, EditCommandCanExecute)
};
view.DataContext = mViewModel;
view.ShowDialog();
}
private void EditCommandExecute(object obj)
{
var editedObject = new WindowEditController().EditChiliModel();
if (editedObject != null)
{
mViewModel.Stock.Add(mViewModel.SelectedChili);
}
}
private bool EditCommandCanExecute(object obj)
{
return mViewModel.SelectedChili != null;
}
The problem is with the EditCommandExecute. Currently I have just put the Code for an AddCommandExecute in there. I unfortunately don't know how to code such an EditCommandExecute.
My WindowEditController looks like this:
public class WindowEditController
{
WindowEdit mView;
public ChiliModel EditChiliModel()
{
mView = new WindowEdit();
WindowEditViewModel mViewModel = new WindowEditViewModel
{
ChiliModel = new ChiliModel(),
OkCommand = new RelayCommand(ExecuteOkCommand),
CancelCommand = new RelayCommand(ExecuteCancelCommand),
};
mView.DataContext = mViewModel;
if (mView.ShowDialog() == true)
{
return mViewModel.ChiliModel;
}
else
{
return null;
}
}
private void ExecuteOkCommand(object obj)
{
mView.DialogResult = true;
mView.Close();
}
private void ExecuteCancelCommand(object obj)
{
mView.DialogResult = false;
mView.Close();
}
I know, that I could let the user edit the SelectedItem inside the DataGrid, but this is not allowed in my task...
Could I maybe use the same window as for my AddCommand? Basically they should look the same, the EditWindow should just already contain the information of the SelectedItem.
I looked up almost every entry similar to this topic, but I did not find a simple solution. Or a solution which I was able to understand with my bad coding skills :( ...
I would be very happy if you guys could help me. Please keep it simple for this newbie :)
What I already tried:
I tried to add a CommandParameter to my Button looking like this: CommandParameter="{Binding SelectedItem, ElementName=StockDataGrid}"
But this still didn't open the window containing the data of the SelectedItem. It just opened a completely new Window for a new Item.
Use CommandParameter just after the Command property, and bind it to the SelectedItem of the DataGrid.
For example, suppose that you DataGrid has the attribute Name=MyDataGrid.
The Button becomes:
<Button Content="Edit"
Margin="5,5,0,5"
Width="100"
Command="{Binding EditCommand}"
CommandParameter="{Binding SelectedItem, ElementName=MyDataGrid}"/>
When EditCommandExecute(object obj) is executed, obj is actually the current SelectedItem that you want.
I would like to pass a Xamarin.Forms.Button in it's own Command as the CommandParameter to my ViewModel. I know how to achieve this from the code behind e.g. ...
XAML (with most properties missed out for brevity)
<Button x:Name="myButton"
Text="My Button"
Command="{Binding ButtonClickCommand}"/>
XAML.cs
public partial class MyTestPage
{
public MyTestPage()
{
InitializeComponent();
myButton.CommandParameter = myButton;
}
}
ViewModel
public class MyViewModel : ViewModelBase
{
public MyViewModel()
{
ButtonClickCommand = new Command(
(parameter) =>
{
var view = parameter as Xamarin.Forms.Button;
if (view != null)
{
// Do Stuff
}
});
}
public ICommand ButtonClickCommand { get; private set; }
}
... BUT is it possible to declare the CommandParameter in the XAML itself? Or in other words what is the binding syntax to set the parameter to the button itself?
<Button x:Name="myButton"
Text="My Button"
Command="{Binding ButtonClickCommand}"
CommandParameter="{[WHAT WOULD GO HERE]}"/>
btw I've already tried CommandParameter="{Binding RelativeSource={RelativeSource Self}}" and that didn't work.
Thanks,
Xamarin.Forms has a Reference markup extension that does just that:
<Button x:Name="myButton"
Text="My Button"
Command="{Binding ButtonClickCommand}"
CommandParameter="{x:Reference myButton}"/>
Although, this is the first time I'm seeing this need, and you probably can better separate your Views from your ViewModels and solve this by using a cleaner pattern, or by not sharing a command across buttons.
<Button x:Name="myButton"
Text="My Button"
Command="{Binding ButtonClickCommand}"
CommandParameter="{x:Reference myButton}"/>
In your ViewModel
public YourViewModel()
{
ButtonClickCommand= new Command(ButtonClicked);
}
private async void ButtonClicked(object sender)
{
var view = sender as Xamarin.Forms.Button;
}
A simple method would be:
In XAML:
<Button Text="BUTTON-TEST"
Clicked="Avaliar"
CommandParameter="like"/>
In C#:
private void Avaliar(object sender, EventArgs e)
{
Console.WriteLine(((Button)sender).CommandParameter);
}
<Button x:Name="myButton"
Text="My Button"
Command="{Binding ButtonClickCommand}"
CommandParameter={Binding RelativeSource=
{RelativeSource
Mode=FindAncestor,
AncestorType={x:Type Button}}/>
Should work, but im still at a loss why you need the button? The point of MVVM is to seperate Data and UI. everything you should need todo to the button can be done via DataBindings.
If the above doesnt work, the only other thing to try is to give the button an x:Key and CommandParamter = {StaticResource 'x:Key'}
I'm new to C# and this is my first WPF project. I am following this tutorial (using their implementation of RelayCommand and attempting to use MVVM. I am implementing a clone of the standard Windows calculator. I would like to find a way to group functionality of similar buttons as what I am doing seems clumsy.
For exmaple, here is my my XAML of three buttons
<Button Content="_7" Focusable ="False" Command="{Binding Seven}" Style="{DynamicResource NumberButton}" Margin="0,134,184,129"/>
<Button Content="_8" Focusable ="False" Command="{Binding Eight}" Style="{DynamicResource NumberButton}" Margin="46,134,138,129"/>
<Button Content="_9" Focusable ="False" Command="{Binding Nine}" Style="{DynamicResource NumberButton}" Margin="92,134,92,129"/>
Here is the ICommands for those:
public ICommand Nine { get { return new RelayCommand(NineExecute); } }
public ICommand Eight { get { return new RelayCommand(EightExecute); } }
public ICommand Seven { get { return new RelayCommand(SevenExecute); } }
and the methods:
void NineExecute()
{
NumberPressed("9");
}
void EightExecute()
{
NumberPressed("8");
}
void SevenExecute()
{
NumberPressed("7");
}
What should I investigate in order to group similar function buttons such as numbers into a single ICommand, with a single method that can determine the sender - while still not putting code behind in the Window class as the article warns against.
Xlam code for a button (supposing that you defined your data context):
<....DataContext>
<loc:Commands/>
</....DataContext>
<Button Content="_9"
Command="{Binding Path=ShowMeABox}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content}"/>
Our dummy command (using RelayCommand<T> from the provided link):
public class Commands
{
private static readonly ICommand _showShowBoxCommand =
new RelayCommand<string>(str => MessageBox.Show(str));
public static ICommand ShowMeABox { get { return _showShowBoxCommand; } }
}
That's it.
FYI.
It's seems that you explicitly specify button size which is generally a bad practice. To position your buttons use stack or wrap panel, or grid/uniformgrid.
Read info on styles and templates to increase code reuse.
Example:
<UniformGrid Columns="3" Rows="3">
<UniformGrid.DataContext>
<loc:Commands/>
</UniformGrid.DataContext>
<UniformGrid.Resources>
<Style TargetType="Button">
<Setter Property="Command" Value="{Binding ShowMeABox}"/>
<Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content}"/>
</Style>
</UniformGrid.Resources>
<Button Content="_1"/>
<Button Content="_2"/>
<Button Content="_3"/>
<Button Content="_4"/>
<Button Content="_5"/>
<Button Content="_6"/>
<Button Content="_7"/>
<Button Content="_8"/>
<Button Content="_9"/>
</UniformGrid>
May be it's possible to bind Enumerable.Range(0,10) to populate control automatically in the MVVM fashion.
Good luck!
Use the CommandParameter property - that way you can bind all of your buttons to the same Command but with different CommandParameter for each number (ie, the CommandParameter should be an integer representing which button as actually pressed)
I would personally write this using a constructor:
public YourType()
{
this.Seven = new RelayCommand( () => NumberPressed("7"));
this.Eight = new RelayCommand( () => NumberPressed("8"));
this.Nine = new RelayCommand( () => NumberPressed("9"));
}
public ICommand Nine { get; private set; }
public ICommand Eight { get; private set; }
public ICommand Seven { get; private set; }
Note that it may also make sense to use the CommandParameter, and a single command. Many frameworks provide a variation on RelayCommand/ActionCommand/etc which accept a command parameter, which you can then specify in XAML. That specific implementation doesn't allow it, but many do, and will map to a method which gets the CommandParameter as a parameter directly.