I have code like this:
<Button x:Name="ExpandSearchCriteriaButton" Command="{Binding ExpandSearchCriteriaCommand}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding StaysOpenLeaveCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding StaysOpenEnterCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Popup StaysOpen="{Binding PopupStaysOpen, Mode=TwoWay}" IsOpen="{Binding PopupIsOpen, Mode=TwoWay}" PlacementTarget="{Binding ElementName=ExpandSearchCriteriaButton}">
//my content here
</Popup>
And now in C#:
private void execExpandSearchCriteriaCommand()
{
if (!PopupIsOpen)
{
PopupIsOpen = true;
}
else
{
PopupIsOpen = false;
}
}
private void execStaysOpenEnterCommand()
{
PopupStaysOpen = true;
}
private void execStaysOpenLeaveCommand()
{
PopupStaysOpen = false;
}
private bool _popupIsOpen;
public bool PopupIsOpen
{
get { return _popupIsOpen; }
set {
_popupIsOpen = value;
RaisePropertyChanged("PopupIsOpen");
}
}
private bool _popupStaysOpen;
public bool PopupStaysOpen
{
get { return _popupStaysOpen; }
set {
_popupStaysOpen = value;
RaisePropertyChanged("PopupStaysOpen");
}
}
The problem is that when my popup is opened by clicking
ExpandSearchCriteriaButton
then
MouseEnter
trigger should change my
PopupStaysOpen
property to true. BThat's unfortunately not happened (tested in console) because trigger basically isn't working when I hover my button and it should, because when popup is closed, it happens. Because of that, when I click button when popup is opened, my popup disappears for while and reappears and if after that I click button it's finally working what's not my target. I want it to close for the first, not second click.
I think, that behavior you see is correct. The trigger for Button doesn't work only if PopUp has StaysOpen=false(for StaysOpen=true it works), this means PopUp captures the mouse events for to be closed(set IsOpen to false) on first click. So if you set StaysOpen to false, the PopUp starts to catch mouse events.
Related
I have the following popup where a user is able to enter three fields and when they click 'ok'. The popup should simply disappear. As of now, when I click on the ok button, nothing happens, the popup just stays there, the same goes for when I click the 'Cancel' button, nothing happens either. What am I missing that when I press the 'OK' button, it does not disappear? Why are the buttons not doing anything when I click on them?
EDIT:
After placing a breakpoint on my ok button logic, I get a hit on that, however, I think my main question here is if there is a way for the popup to close after clicking on ok, hence, the user is done entering data.
As for the cancel button, it does not trigger when the breakpoint when clicking on the button.
XAML CODE
<Border Grid.Column="0" Margin="5"
Grid.Row="2">
<WrapPanel HorizontalAlignment="Right">
<Button x:Name="btnCancel" Command="{Binding Path=CloseCommand}"
Content="_Cancel" Margin="4,2" MinWidth="60"/>
<Button x:Name="btnOk" Command="{Binding Path=OKCommand}"
Content="_OK" Margin="4,2" MinWidth="60"/>
</WrapPanel>
</Border>
ViewModel Code
public event CancelHandler OnCancel;
public delegate void CancelHandler();
public ICommand CancelCommand
{
get { return new RelayCommand(c => OnCancelLock()); }
}
public ICommand OKCommand
{
get { return new RelayCommand(c => OnOKLock()); }
}
protected void OnOKLock()
{
var currentSetting = AppSession.Repository.Settings.Find(SettingQuery.ID == new ID("LockedOutDate"));
currentSetting[0].Value = LockedOutDate;
AppSession.Repository.Settings.Save(currentSetting[0]);
currentSetting = AppSession.Repository.Settings.Find(SettingQuery.ID == new ID("LockedOutBy"));
currentSetting[0].Value = LockedOutBy;
AppSession.Repository.Settings.Save(currentSetting[0]);
currentSetting = AppSession.Repository.Settings.Find(SettingQuery.ID == new ID("LockedOutFor"));
currentSetting[0].Value = LockedOutFor;
AppSession.Repository.Settings.Save(currentSetting[0]);
currentSetting = AppSession.Repository.Settings.Find(SettingQuery.ID == new ID("IsUsersLockedOut"));
currentSetting[0].Value = "1";
AppSession.Repository.Settings.Save(currentSetting[0]);
}
protected void OnCancelLock()
{
OnCancel();
}
The problem you have is right here:
<Button x:Name="btnCancel" Command="{Binding Path=CloseCommand}"
Content="_Cancel" Margin="4,2" MinWidth="60"/>
You defined your binding to be CloseCommand, but in your ViewModel code you wrote:
public ICommand CancelCommand
{
get { return new RelayCommand(c => OnCancelLock()); }
}
So either change it to CloseCommand in your ViewModel or CancelCommand in your XAML file.
I am using MaterialsDesigninXAML. When trying to use the snack bar with the MVVM method I ran into an issue that was preventing the Snackbar from displaying a message. I have included the ViewModel and the associated XAML code. I had a look through the MaterialDesign Snackbar Wiki but was unable to see what I had missed.
MainScreenViewModel
private SnackbarMessageQueue m_messagequeue;
public MainScreenViewModel()
{
MESSAGEQUEUE = new SnackbarMessageQueue(TimeSpan.FromMilliseconds(8000));
}
public SnackbarMessageQueue MESSAGEQUEUE { get { return m_messagequeue; } set {m_messagequeue = value; OnPropertyChanged("MESSAGEQUEUE"); } }
public void On_message_click()
{
Task.Factory.StartNew(() => MESSAGEQUEUE.Enqueue("Wow, easy!"));
}
}
MainScreen.xaml
<Button Content="message" Style="{StaticResource MaterialDesignRaisedDarkButton}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:CallMethodAction TargetObject="{Binding}"
MethodName="On_message_click"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<materialDesign:Snackbar MessageQueue="{Binding MESSAGEQUEUE}" />
But when running I noticed the issue that the Dispatcher cant finds the snack bar. I am wondering why this is or if I am missing something to get the messages to appear on the snack bar.
//find a target
var snackbar = await FindSnackbar(exemplar.Dispatcher);
//show message
if (snackbar != null){...}
I am triggering password change event and command action
xaml
<PasswordBox VmWindow:PasswordHelper.Attach="True" Height="25" Width="180" HorizontalAlignment="Left"
FontFamily="Arial" FontSize="11" BorderBrush="#FF959BA0" TabIndex="2"
VmWindow:PasswordHelper.Password="{Binding Path=Password, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="PasswordChanged">
<i:InvokeCommandAction Command="{Binding ChangePasswordCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</PasswordBox>
Password changed event code:
private static void PasswordChanged(object sender, RoutedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
SetIsUpdating(passwordBox, true);
SetPassword(passwordBox, passwordBox.Password);
SetIsUpdating(passwordBox, false);
}
Command Action
public ICommand ChangePasswordCommand { get; private set; }
public LoginViewModel ViewModel { get; set; }
private void ExecuteChangePasswordCommand()
{
try
{
if (loginModel != null)
{
loginModel.LoginPassword = Password;
}
}
catch (Exception exception)
{
}
}
Problem:
What is happening intially when application loads i enter char in textbox the "Event fires first and then action which ok normal senario",but when i press second char "my Action fires first then trigger that is the problem"
I don't know weather it is predefined process or am i doing something wrong .Because according to me order should always Event,action not Action,event
Please let me know where i am wrong.
Finally after spending a lot of time i am able to solve the above problem with some additional changes
Add Reference of Microsoft.Expressions.Interactions
Add two refrences:
xmlns:i="clrnamespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei=http://schemas.microsoft.com/expression/2010/interactions
Done few changes in password box:
<PasswordBox VmWindow:PasswordHelper.Attach="True" Height="25" Width="180" HorizontalAlignment="Left"
FontFamily="Arial" FontSize="11" BorderBrush="#FF959BA0" TabIndex="2"
VmWindow:PasswordHelper.Password="{Binding Path=Password, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="PasswordChanged">
<ei:CallMethodAction TargetObject="{Binding}" MethodName="changePassword"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</PasswordBox>
Create a Method in Your LoginViewModel
public void changePassword(object sender, RoutedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
loginModel.LoginPassword = passwordBox.Password;
}
Done With changes its clean MVVM with no code behind now
Before my page load I check some data for the state of the ToggleButton:
private void CheckVoteState()
{
var getVoteState = from state in SelectedActivity.UserVotes
select state.Type;
string voteState = getVoteState.FirstOrDefault();
if (voteState == "positive")
{
VoteStateText = LocalizedStrings.Get("VoteStateUnLikeText");
VoteState = true;
}
else
{
VoteStateText = LocalizedStrings.Get("VoteStateLikeText");
VoteState = false;
}
}
But I have this 2 commands, and ofcours when my page loads one of this 2 commands triggers:
public RelayCommand LikeCommand
{
get
{
return new RelayCommand(async() =>
{
//Call Like Api
await _IDataService.VoteForProposition(_SelectedActivity.Object.Id);
});
}
}
public RelayCommand UnLikeCommand
{
get
{
return new RelayCommand(async() =>
{
//Call Unlike Api
await _IDataService.RemoveVoteOnProposition(_SelectedActivity.Object.Id);
});
}
}
I don't want them to get triggerd when the pages loads, but only when the user checks or unchecks.
This is my xaml side:
<ToggleButton Content="{Binding VoteStateText}"
Foreground="White"
Background="LightGray"
Margin="10,-10,10,0"
BorderThickness="0"
HorizontalAlignment="Stretch"
IsChecked="{Binding VoteState}">
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Checked">
<core:InvokeCommandAction Command="{Binding LikeCommand}" />
</core:EventTriggerBehavior>
<core:EventTriggerBehavior EventName="Unchecked">
<core:InvokeCommandAction Command="{Binding UnLikeCommand}" />
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
</ToggleButton>
In the past I solved this with _isPageLoaded boolean. Simply set it to true in Page_Loaded event handler and check in your commands.
I have this XAML code:
<DataGrid>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<prism:InvokeCommandAction Command="{Binding AddedSelectedClaimsCommand}" TriggerParameterPath="AddedItems" />
<prism:InvokeCommandAction Command="{Binding RemovedSelectedClaimsCommand}" TriggerParameterPath="RemovedItems" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseDoubleClick">
<prism:InvokeCommandAction Command="{Binding ViewDetailsCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<DataGrid.ContextMenu>
<ContextMenu >
<MenuItem Header="View details" Command="{Binding ViewDetailsCommand}"/>
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
It works fine without the MouseDoubleClick EventTrigger. But when I added in the double click ability, the data grid suddenly appeared greyed out and rows could no longer be selected. Why?
Your canExecuteMethod delegate must be returning false for some reason, review your ViewModel and make sure all bellow is in place for you:
In you command initialization make sure you set canExecuteMethod delegate as well as your command action:
ViewDetailsCommand = new DelegateCommand(ExecuteViewDetailsCommand,
CanExecuteViewDetailsCommand);
Then goes your logic that verify if preconditions are met to execute this command. At the end it will enable or disable the associated control(s) for this command.
private bool CanExecuteViewDetailsCommand() {
return null != SelectedDetail;
}
If command successfully passed preconditions tests, then it can safely execute its method:
private void ExecuteViewDetailsCommand()
{
NavigateTo("DetailView",SelectedDetail);
}
You should have SelectedDetail property in place too (read/write):
Detail selectedDetail;
public Detail SelectedDetail
{
get { return selectedDetail; }
set {
SetProperty(ref selectedDetail, value);
RaiseCanExecuteEvents();
}
}
Note above RaiseCanExecuteEvents method invokation, this is a convenience method where you can force related commands validations:
protected virtual void RaiseCanExecuteEvents()
{
ViewDetailsCommand.RaiseCanExecuteChanged();
}