wpf Snack bar not showing messages - c#

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){...}

Related

WPF MVVM trigger on opened popup stopping working

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.

Password change event behaviour not working properly in prism using mvvm

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

Windows Phone 8.1 ToggleButton checked and unchecked triggers?

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.

Creating Single ListBoxItem

I have an existing solution of my WPF UI but it's ViewModel implementation is clunky and I'm looking to improve.
Below is a gif of how my current system works:
There's a Current Task (note: only ever one item)
There's a Task List for Tasks (note: possibly many) that need to run in the future
When the user selects one list box, the other selection is removed
The problem is, I'm implementing Current Task as a Listbox with only one item. This means I have to lug around a backing IList for the ItemSource and another property for the SelectedItem.
Is there another control I can use to behave like ListBoxItem, but I can bind my CurrentTask directly to it and not have to muck around with an List for ItemSource as well?
EDIT: To get the selection to go away when one listbox is selected, I have a trigger set up on the SelectionChanged event.
(deleted my previous answer)
It occurs to me that at least part of the functionality you're looking for is implemented by the RadioButton class. Multiple RadioButtons in the same scope guarantee that only one of them is selected. You'll probably have to do a little work to make sure that your RadioButtons can be scoped correctly in your UI, and you'll probably need to retemplate some things to get exactly the UI you need. Additionally, RadioButton does not have a SelectedItem/SelectValue property to which it can write to, because WPF provides no built-in mechanism for multiple controls to safely bind to a "SelectedWhatever" property. But you could roll this yourself pretty easily with codebehind or triggers.
Here's the implementation I went with:
XAML View
<!-- The Current Task box -->
<ListBox x:Name="CurrentTaskBox" FlowDirection="RightToLeft" Background="{StaticResource WhiteBrush}">
<ListBoxItem IsSelected="{Binding CurrentTaskSelected, Mode=TwoWay}" Content="{Binding CurrentTask.TaskId}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Selected">
<command:EventToCommand Command="{Binding SetTaskDetailsFromCurrentTaskCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBoxItem>
</ListBox>
<!-- The Task List box -->
<ListBox x:Name="TaskListBox" SelectedIndex="{Binding TaskListIndex}" SelectedValue="{Binding TaskListSelection}" IsSynchronizedWithCurrentItem="True" HorizontalContentAlignment="Stretch" ItemsSource="{Binding TaskList}" FlowDirection="RightToLeft" DisplayMemberPath="TaskId" Margin="3">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<command:EventToCommand Command="{Binding SetTaskDetailsFromTaskListCommand}" CommandParameter="{Binding SelectedItem, ElementName=TaskListBox}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
ViewModel
/* Omitted most INPC property declarations...kinda boring */
public ICommand SetTaskDetailsFromCurrentTaskCommand { get { return new RelayCommand(SetTaskDetailsFromCurrentTask); } }
public ICommand SetTaskDetailsFromTaskListCommand { get { return new RelayCommand<TaskScheduleSequenceDto>(async taskSelection => await SetTaskDetailsFromTaskList(taskSelection)); } }
private bool _currentTaskSelected;
public bool CurrentTaskSelected
{
get
{
return _currentTaskSelected;
}
set
{
Set(() => CurrentTaskSelected, ref _currentTaskSelected, value);
}
}
private async Task SetTaskDetailsFromTaskList(TaskScheduleSequenceDto taskListSelection)
{
if (taskListSelection == null)
{
return;
}
var taskDetails = await _broker.RetrieveTaskDetails(taskListSelection.TaskId);
TaskDetails = taskDetails;
CurrentTaskSelected = false;
}
private void SetTaskDetailsFromCurrentTask()
{
TaskDetails = CurrentTask;
TaskListSelection = null;
CurrentTaskSelected = true;
}
This works fine and only requires that I have a single CurrentTask property in my VM, which I think is much cleaner.

Sending an object with a command parameter

I am using PRISM to develop my Windows Phone app using the MVVM design pattern. I need to pass my SelectedItem object from my LongListSelector through my delegate command into my method.
I can do that. The problem is, I'm passing in the wrong object. I don't know if it's a design problem or I am binding improperly.
I need the object to be an Album object. What I'm getting instead is either null or my ViewModel. (I've changed the code a few times and those are the only things I can get.)
XAML
<phone:LongListSelector x:Name="AlbumList" ItemsSource="{Binding Albums}"
Margin="10,0,0,0" LayoutMode="Grid" GridCellSize="200, 200"
ItemTemplate="{StaticResource AlbumTemplate}"
toolkit:TiltEffect.IsTiltEnabled="True"
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding DataContext.SelectAlbumCommand, ElementName=ContentPanel}"
CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</phone:LongListSelector>
ViewModel
private ObservableCollection<Album> _albums;
public ObservableCollection<Album> Albums
{
get { return _albums; }
set
{
if (value != null)
{
_albums = value;
NotifyPropertyChanged();
}
}
}
private Album _selectedAlbum;
public Album SelectedAlbum
{
get { return _selectedAlbum; }
// code removed as it is not needed; the object is null when trying to set.
}
public void AlbumSelected(object p)
{
App.Dispatcher.BeginInvoke(() =>
{
SelectedAlbum = (Album)p;
});
////Navigate("/Views/PhotosListPage.xaml");
}
//command that takes an object as parameter.
_selectAlbumCommand = new DelegateCommand<object>(this.AlbumSelected);
In case you merely want to set the SelectedAlbum by your SelectAlbumCommand, why don't you try binding the SelectedItem to SelectedAlbum instead?
<phone:LongListSelector x:Name="AlbumList" ItemsSource="{Binding Albums}"
SelectedItem="{Binding SelectedAlbum}" />
In case you actually want to pass the SelectedItem to the SelectedAlbumCommand (for some other reason), you should bind the CommandParameter to the SelectedItem of the LongListSelector
<i:InvokeCommandAction Command="{Binding DataContext.SelectAlbumCommand, ElementName=ContentPanel}" CommandParameter="{Binding ElementName=AlbumList, Path=SelectedItem}"/>
Apparently, you cannot use LongListSelector for this. I had to change this to a listbox and it worked fine.
Had I searched harder, I would have found this: How to select an item in LongListSelector using the MVVM-pattern?
and this: WP8 LongListSelector SelectedItem not bindable

Categories

Resources