Users of my WPF Application from time to time are able to fire twice command that is binded to button.
XAML Code:
<Button x:Name="btnAccept"
Style="{StaticResource FlatButtonLarge}"
Height="42"
Command="{Binding Path=SubmitCmd}"
Content="Submit" />
I've got also KeyBindings
<Window.InputBindings>
<KeyBinding Key="F9" Command="{Binding SubmitCmd}" />
</Window.InputBindings>
I am not able to reproduce an error but based on the changes in the database I conclude the command was fired twice one time after time. Is it really posible and how can I prevent such phenomena.
SubmitCmd adds new record to the database and closes form.
Here is the code behind:
vm.SubmitCmd = new RelayCommand(pars => DoSubmit(), pars => vm.CmdSubmitCanExecute, "Submit" );
private void DoSubmit()
{
try
{
if (!vm.LaunchAllowed)
{
this.Close();
}
else
{
vm.LaunchAllowed = false;
bool isOk = DBService.SaveToDB(vm.Dto);
if (isOk)
{
DialogResult = true;
this.Close();
}
else
{
ShowError(this, result);
vm.LaunchAllowed = true;
}
}
}
catch (Exception ex)
{
ShowError(this, ex.Message);
vm.LaunchAllowed = true;
}
}
And ViewModel code:
public ICommand SubmitCmd{ get; set; }
public bool CmdSubmitCanExecute
{
get
{
return LaunchAllowed;
}
}
I have same issue.
In my case i bind a command into two component, here is the wrong code
<pv:PancakeView Grid.Row="3" CornerRadius="30" Margin="24,8,24,16" BackgroundColor="{StaticResource MainGreen}" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" HasShadow="True"
xct:TouchEffect.PressedOpacity="0.7"
xct:TouchEffect.NormalOpacity="1"
xct:TouchEffect.AnimationEasing="{x:Static Easing.CubicInOut}"
xct:TouchEffect.AnimationDuration="100"
xct:TouchEffect.PressedScale="0.9"
xct:TouchEffect.Command="{Binding Checkout}">
<Label Text="CHECKOUT" TextColor="{StaticResource MainWhite}" FontSize="18" FontFamily="{StaticResource PoppinsMedium}" VerticalTextAlignment="Center" HorizontalTextAlignment="Center"/>
<pv:PancakeView.Shadow>
<pv:DropShadow Offset="0,0" Opacity="0.15" BlurRadius="25"></pv:DropShadow>
</pv:PancakeView.Shadow>
<pv:PancakeView.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Checkout}"/>
</pv:PancakeView.GestureRecognizers>
</pv:PancakeView>
At that xaml code, i bind Checkout Command to TapGestureRecognizer and xct:TouchEffect
Remove one of them solve the problem for me.
for your case, i think below approach will work
In KeyBindings area change the binded command to new command like this <KeyBinding Key="F9" Command="{Binding OtherSubmitCmd}" />
Add public ICommand OtherSubmitCmd{ get; set; } to your ViewModel. Then assign same methode for OtherSubmitCmd.
I think I saw this too, but - as you - I was not able to reproduce it. It also was my conclusion.
To solve this I disabled the button right after the command run. So assuming you using mvvm, add a property to it (don't forget to raise the property changed event) and bind the IsEnabled-Property of your button the the new property
Related
googling for this showed me that this is often a problem but never reallay solved.
I do have an App/Prgramm in C#, i'll try to be mvvm conform.
I do have an window, in it a UserControl show different views.
One of my view contains a textbox, the text of the textbox is bound to a proptery of the VM.
My textbox got 2 inputbindings, for "enter" and "return" - both leading to same command.
On hitting "enter" the value of the textbox should be processed, the textbox shoud be cleared and refocused ... This works .... One Time ....
Clearing the textbox with String.Empty breaks the Bindings ... this could be found in several postings here ... the most Solution is textboxname.clear() ...
But i dont have the "textboxname" in the viewmodel, only in code-behind, but all my logic is in the VM ... So can somebody pls help me sort things out, how i could clear the textbox without breaking the bindings to input text and hit enter more then one time ?
My Code
<TextBox x:Name="tb_checkinbox" Grid.Row="0" Grid.Column="1" Width="200" Height="25" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding CheckInNumber}">
<TextBox.InputBindings>
<KeyBinding Command="{Binding OnCheckInEnterCommand}" Key="Return"/>
<KeyBinding Command="{Binding OnCheckInEnterCommand}" Key="Enter"/>
</TextBox.InputBindings>
</TextBox>
public CheckinVM()
{
OnCheckInEnterCommand = new RelayCommand(OnCheckInEnter, CanCheckInEnter);
}
private string _checkInNumber;
public string CheckInNumber
{
get { return _checkInNumber; }
set { SetProperty(ref _checkInNumber, value); }
}
public ICommand OnCheckInEnterCommand { get; set; }
public void OnCheckInEnter(object value)
{
CheckInNumber = String.Empty;
/// More to do
}
public bool CanCheckInEnter(object value)
{
return true;
}
The assignment
CheckInNumber = string.Empty;
does not "clear" any Binding. Your conclusion is wrong.
You do however only get empty strings - after clearing - in the setter of the CheckInNumber property. In order to get property updates not only when the TextBox loses focus or you reset the source property, set UpdateSourceTrigger=PropertyChanged on the Text Binding:
<TextBox ... Text="{Binding CheckInNumber, UpdateSourceTrigger=PropertyChanged}">
I have a <List> that adds and removes elements by calling a modal from a <Button> as shown in the figure.
When lifting the modal, I show the user the elements that can be associated to the main list and also indicate with a <Switch> if these elements are added or not, with the objective that when pressing the switch add or remove elements from the main list
The problem is that when the modal is lifted, the method that adds and deletes elements to the list is executed and every time I raise the modal, my records are duplicated, as shown in the figure
This is due to the fact that when lifting the modal, the method that adds or removes chemicals is executed, this is called every time the property value that is binded to the <Switch> in the view changes
Why is this happening? How can I avoid it?
Then I present my code ...
MODAL.XAML:
<StackLayout
BindingContext="{Binding AgregarSustancia}">
<ListView
ItemsSource="{Binding ListaSustancias}"
SelectedItem="{Binding SelectedSustancia}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<StackLayout Orientation="Vertical">
<Label Text="{Binding NombreSustancia}"
HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand"/>
</StackLayout>
<Switch
OnColor="{StaticResource das.color.verde}" HorizontalOptions="EndAndExpand"
VerticalOptions="Start"
IsToggled="{Binding SustanciaAsociada, Mode=OneWay}">
</Switch>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout/>
AGREGARSUSTANCIA.CS:
bool sustanciaAsociada;
[JsonProperty(PropertyName = "chemicalIsAssociateWithInstallation")]
public bool SustanciaAsociada
{
get
{
return sustanciaAsociada;
}
set
{
if (value != sustanciaAsociada)
{
sustanciaAsociada = value;
AsociarDesasociar(sustanciaAsociada);
}
}
}
//METHOD THAT ADDS OR ELIMINATES DEPENDING ON THE VALUE OF THE PARAMETER
private async void AsociarDesasociar(bool sustanciaAsociada)
{
//ADD TO LIST
if (sustanciaAsociada)
{
}
else //REMOVE TO LIST
{
}
}
Then my ViewModel that fills the modal list
VIEWMODEL.CS: (MODAL)
#region Constructor
public AgregarSustanciaViewModel(ObservableCollection<AgregarSustancia> listaAgregarSustancia)
{
navigationService = new NavigationService();
ListaSustancias = new ObservableCollection<AgregarSustancia>();
listaSustanciasAux = new List<AgregarSustancia>(listaAgregarSustancia);
ListaSustancias = listaAgregarSustancia;
}
#endregion
How can I prevent the method AsociarDesasociar() in the Get-Set property of the Switch from executing the modal? How can I encapsulate this method?
Any help for me?
create a bool InitComplete and initialize it to false. This will prevent AsociarDesasociar from executing before initialization is complete
if (value != sustanciaAsociada)
{
sustanciaAsociada = value;
if (InitComplete) {
AsociarDesasociar(sustanciaAsociada);
}
}
after your class has finished whatever initialization is required, then set InitComplete = true
Normally you can call void function(from ViewModel) in View by simply:
Button Name = VoidFunctionInViewModel
Button Command={Binding Path=VoidFunctionInViewModel}
But when accessing this function inside a DialogHost, the void function isn't triggered.
I have tried retrieving a string field to the DialogHost and it works fine, but when it comes to commands on buttons it doesn't work.
MainViewModel.cs Commands:
public async void OpenDialog()
{
var confirm = new ConfirmationView{DataContext = this};
await DialogHost.Show(confirm);
}
public void Accept()
{
Console.WriteLine("It Failed!");
}
public string Success {get; set;} = "Success"
ConfirmationView.xaml:
<Button Command="{Binding Path=Accept}" Content="Accept"/>
<Button Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}" Content="Cancel"/>
<TextBlock Name="Success"/>
MainView.xaml:
<materialDesign:DialogHost DialogTheme="Inherit" CloseOnClickAway="True">
</materialDesign:DialogHost>
The Property "Success" is successfully used and shown by the DialogHost.
But the Button "Accept" with the command Accept isn't triggered by the DialogHost.
The Button "Cancel" is working, with the command from materialDesign.
Shouldnt it be this way for caliburn.micro?
<Button x:Name="Accept" Content="Accept"/>
Using the Command="" syntax works only by using ICommand or RelayCommand in the ViewModel, or? At least that is how i understood caliburn.micro so far.
If that doesnt work, you could try this. This worked for me in the drawerHost, where caliburn.micro Command binding failed for me:
<Button cal:Message.Attach="[Event Click] = [Action Accept()]" Content="Accept" />
other sources with dialog examples, which might be usefull:
https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/wiki/Dialogs
https://github.com/Keboo/MaterialDesignInXaml.Examples
I am trying to dynamically show/hide button inside Xamarin Forms ContentPage.
I have two buttons in my XAML code:
<StackLayout Orientation="Vertical">
<Button x:Name="start_btn" Clicked="startPanic">
<Button.Text>START</Button.Text>
</Button>
<Button x:Name="stop_btn" IsVisible="false">
<Button.Text>STOP</Button.Text>
</Button>
</StackLayout>
Corresponding C# code:
public partial class PanicPage : ContentPage
{
private Button startBtn;
private Button stopBtn;
public PanicPage ()
{
InitializeComponent ();
startBtn = this.FindByName<Button> ("start_btn");
stopBtn = this.FindByName<Button> ("stop_btn");
}
private void startPanic(object sender, EventArgs args){
Device.BeginInvokeOnMainThread (() => {
startBtn.IsVisible = false;
stopBtn.IsVisible = true; // DOESN'T WORK, button still will be hidden
});
}
}
When I set isVisible property in XAML, it doesn't react for any property change in event method (startPanic). How can I fix it?
Change your code in xmal file and write properties for start and stop button
<Button x:Name="start_btn" Clicked="startPanic" IsVisible="{Binding IsStartVisible}">
<Button.Text>START</Button.Text>
</Button>
<Button x:Name="stop_btn" IsVisible="{Binding IsStopVisible}">
<Button.Text>STOP</Button.Text>
</Button>
In ViewModel write following property and similar for start button and set IsStopVisible =true/false based on your logic
private bool _isStopVisible;
public bool IsStopVisible{
get {
return _isStopVisible;
}
set {
_isStopVisible= value;
RaisePropertyChanged ("IsStopVisible");
}
}
Maybe I'm late but I was searching this too without success. This may be useful for someone.
objectView.SetValue(IsVisibleProperty, false); // the view is GONE, not invisible
objectView.SetValue(IsVisibleProperty, true);
It should work just fine. I copied your code and cleaned it up a bit, it shows the STOP button, then I
A few remarks:
use the short property where possible <Button Text="X"/>, it's
easier to read
when you add a XAML page the IDE adds a .xaml.cs file next to it and generates another .g.cs that you don't see. The .g.cs file
contains generated code that finds all the x:Name'd elements and
defines placeholders for them, no need to find them by name yourself
all UI-initiated events are executed on the UI thread, no need to do that explicitly
Here's the XAML, same as yours just tighter and added Margin so the button is visible
<StackLayout Orientation="Vertical" Margin="20">
<Button x:Name="start_btn" Clicked="startPanic" Text="START" />
<Button x:Name="stop_btn" Text="STOP" IsVisible="false" />
</StackLayout>
And the code behind:
public partial class TestPage : ContentPage
{
public TestPage ()
{
InitializeComponent ();
}
private void startPanic(object sender, EventArgs args){
Device.BeginInvokeOnMainThread (() => {
start_btn.IsVisible = false;
stop_btn.IsVisible = true;
});
}
}
Use the Visibility property of view.
for example if u want to make your button invisible you can do
if(condition)
{
button.Visibility=ViewStates.Invisible;
}
else
{
button.Visibility=ViewStates.Visible;
}
I am using PasswordBox and I want to detect whenever the user typed there anything, if yes I need to change Button status to enabled. How can I check if user types anything
in the PasswordBox?
It behaves differently from TextBox since you can't bind it to text
and when user types anything raises some event. Any idea?
I have tried with the code below, but I get errors:
<PasswordBox>
<i:Interaction.Triggers>
<EventTrigger EventName="KeyDown">
<si:InvokeDataCommand Command="{Binding MyCommand}" />
</EventTrigger>
</i:Interaction.Triggers>
</PasswordBox>
You can use PasswordChanged event which fires when the string in the passwordbox changes:
XAML Part:
<PasswordBox Name="pwdBox" PasswordChanged="pwdBox_PasswordChanged" />
<Button Name="someButton" IsEnabled="False" Click="someClickEvent" />
C# Part:
private void pwdBox_PasswordChanged(object sender, RoutedEventArgs e)
{
somebutton.IsEnabled = String.IsNullOrWhiteSpace(pwdBox.Password));
}
Please note that MSDN says
When you get the Password property value, you expose the password as plain text in memory. To avoid this potential security risk, use the SecurePassword property to get the password as a SecureString.
Therefore the following code may be preferred:
private void pwdBox_PasswordChanged(object sender, RoutedEventArgs e)
{
btn.IsEnabled = pwdBox.SecurePassword.Length == 0;
}
If you only have access to viewModel, then you may use attached properties such that you create a bindable password or securepassword, as in this example
You can use the PasswordChanged event via Interactions like this:
XAML
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<PasswordBox BorderBrush="#FFB0B1AB"
Width="100"
Height="25"
VerticalAlignment="Bottom">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PasswordChanged">
<i:InvokeCommandAction Command="{Binding PasswordChangedCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</PasswordBox>
RelayCommand
private ICommand _passwordChangedCommand = null;
public ICommand PasswordChangedCommand
{
get
{
if (_passwordChangedCommand == null)
{
_passwordChangedCommand = new RelayCommand(param => this.PasswordChanged(), null);
}
return _passwordChangedCommand;
}
}
private void PasswordChanged()
{
// your logic here
}
Some useful links
PasswordBox in WPF Tutorial
Binding to PasswordBox in WPF (using MVVM)
How to bind to a PasswordBox in MVVM