Intermittent error while using EventTriggerBehavior/InvokeCommandAction - c#

Dеаr Colleagues,
I'm having issues with the following code:
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="BeforeTextChanging">
<core:InvokeCommandAction Command="{Binding ConfirmEmailCommand, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
I want to emphasize, that the command triggers MOST of the times. The code works. The problem is, it sometimes doesn't. Command isn't called by the evens that otherwise will call it.
The behavior belongs to a Textbox inside a TemplatedControl, which exists inside a ContentDialog. I have similar code in other controls that are part of a ContentDialog and they all have such intermittent problems.
Does anyone have experience with such problems and can you elaborate on a possible fix? What order of control construction and property allocation could cause the Command to not be available for invocation during the event?

Related

WPF Getting mouse coordinates within viewmodel

I have a WPF project (C#, MVVM Light, Visual Studio 2010).
I have a bit of a problem regarding separation of concerns (MVVM) which basically is this: I have a command in a view model. I have a context menu that I want to call that command. So far so good. The problem is that the command needs to coordinates that the mouse was clicked.
To be a little more specific, the ContextMenu only appears if you click on a particular Canvas control, and it's the coordinates within said Canvas control that I want.
The easy way to do this is to manage it all in the code behind of the XAML document (and I have been able to do it that way), but I'd rather have it within my ViewModel if I can do so. The reason is that there are calls to my data model within this command so we end up with a problem of separation.
I am aware of PassEventArgsToCommand, and I'm aware that it's a bad practise, however in this case I'm not sure I can see a way around it. So for the moment I did try that, and it looks like this:
<ContextMenu x:Key="BackgroundMenu">
<MenuItem Header="Add new node here">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cmd:EventToCommand Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.DataContext.AddNewNodeAtLocationCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
</ContextMenu>
So now my command, within the view model, looks like this:
void AddNewNodeAtLocationExecute(RoutedEventArgs e)
{
return;
}
Within that method I'd like to get those mouse coordinates, but I don't know if it's possible. e.OriginalSource is 'MenuItem', which doesn't help much.
So how can I do this? Can I do this? Or should I just have this one command handled by the code behind? Said code will involve a call to the database, which is why I'm being so particular about the separation.
Thanks in advance.
Well I stumbled across this question which speaks about separation of concerns and what not.
In the end I did a merging of the two ideas I had. Firstly, the ContextMenu simply links to the code behind. At that point I get the coordinates I want. Then that code behind gets the DataContext of the view (where the command I want is) and calls the Execute method (having first checked the 'can' method).
I suppose it's as ideal as you're going to get.

Setting focus to textbox upon method-execution

I have 2 different commands called; whom each perform some actions and reveal a form. I want them to set focus to the first textbox in that form when they set the Visible property to true.
I've seen all kinds of SO-articles on this subject, but I just can't seem to puzzle the pieces together. I'm working with MVVM, but all MVVM-solutions look pretty extensive for something that is just a QoL-improvement. I do have some code in my codebehind file, so I assumed I could just put it there and have a quicker/cleaner solution, but those I could mostly find for start-up focus.
I've messed around with the Focusmanager, but that doesn't seem to bring me anywhere either.
The tricky part of the whole construction is the following;
<ListBox Grid.Column="0" Grid.Row="1" Margin="5" IsEnabled="{Binding IsEnabled}" ItemsSource="{Binding DisabledConfigs}" SelectionMode="Extended" SelectedItem="{Binding SelectedConfig}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding SelectionChanged}"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseDoubleClick">
<cmd:EventToCommand Command="{Binding EditConfig}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
The EditConfig-Command triggers a method that checks some properties of the double-clicked object, and either shows a form or not. When it does, the first textbox in that form should receive focus, otherwise nothing of importance happens.
I've been struggling with this stupid QoL-issue for my entire morning now, so I'm prepared to donate my left-kidney to whomever points me in a direction I can cleanly adopt ..
Edit: After a suggestion by AdminSoftDK I tried the following
// Auto-generated
private void nameBoxEdit_IsVisibleChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
{
if (nameBoxEdit.IsVisible)
{
// nameBoxEdit is (quite self-explanatory) the textbox that I want to focus on
nameBoxEdit.Focus();
}
}
I'm convinced this should be pretty close to the solution, but it's not working as is.
Huge shoutout to adminSoftDK for helping me out here
So I finally got the solution, which looks pretty weird to me, but it's working so I'm not complaining;
private void nameBoxAdd_IsVisibleChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
{
if(!nameBoxAdd.IsVisible)
{
nameBoxAdd.UpdateLayout();
// Task.Delay(500); abundant
nameBoxAdd.Focus();
// After testing some more, the Task.Delay(500) is not needed either.
// It's just the combination of UpdateLayout() and Focus()
}
}
I had quite an exstensive list of method-calls and property-checks in here to see if anything worked, an low and behold the focus was granted. I started filtering down, and for some reason the combined effort of UpdateLatyout() and the delayed task on Focus() made it work. Not either on of them (I tried having just one or the other which both put me on non-focus again), but the both of them.
Another weird thing to notice is that the IsVisibleChanged event triggers before actually changing the property. Something I ran across with the debugger..

CommandParameter always passes EventArgs with ElementName binding, no actual binded value

So, with the Behavior SDK I want to bind a Pivot event to my viewmodel. The binding looks like this:
<Pivot Grid.Row="1" x:Name="pvtMain"
ItemsSource="{Binding Items}"
HeaderTemplate="{StaticResource PivotHeaderTemplate}">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="PivotItemLoading">
<Core:InvokeCommandAction Command="{Binding LoadAdditionalData}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</Pivot>
The action that is performed in the Viewmodel looks like this:
private void _CommandLoadAdditionalData(object parameter) {
var test = (parameter as PivotItemEventArgs);
}
The problem is as follows: I'm getting the error: type or namespace name 'PivotItemEventArgs' could not be found (are you missing a using directive or an assembly reference?).
But when I run the project everything works just fine. When dig a little deeper, PivotItemEventArgs does reside in the Windows.UI.Xaml.Controls, but it won't be found in the Shared project.
I'm guessing this happens because a pivot item is no Windows 8 control.
Now I just want the SelectedItem to be passed, instead of EventArgs. I changed my CommandParameter to the following:
<Core:InvokeCommandAction Command="{Binding LoadAdditionalData}"
CommandParameter="{Binding ElementName=pvtMain, Path=SelectedItem}" />
Still, the value is still PivotItemEventArgs. Am I missing something?
So after some struggling, I've stumbled upon the 'solution'.
I bound the command on the PivotItemLoading event. Somehow, at the first load event trigger, the parameter is always of type PivotItemEventArgs.
However, after the second loading, the correct object (the SelectedItem) is being passed along!
I don't know the exact reason, but it's good to know this works.

Can't use long syntax for ActionMessage in Caliburn.Micro

I'm trying to create an action for an attached event which I don't think CM supports out of the box.
This question/answer shows how to do this
using attached events with caliburn micro Message.Attach
but it requires using the long CM ActionMessage syntax, however, when I try to do this I get an 'ActionMessage does not exist in the XML namespace ' where blah is the CM namespace.
All of the examples also show this syntax; at the moment I've just put the code into the view which casts the DataContext to the ViewModel type and calls the appropriate method (I don't like this approach though as it couples the view to the VM and it's inconsistent with the rest of the app)
Anyone have any ideas why I can't see the ActionMessage?
e.g.
<i:Interaction.Triggers>
<Helpers:RoutedEventTrigger RoutedEvent="Helpers:DataChanging.Changing">
<!-- this line throws the error -->
<cal:ActionMessage MethodName="SelectedDataChanged">
<cal:Parameter Value="$eventargs" />
</cal:ActionMessage>
</Helpers:RoutedEventTrigger>
</i:Interaction.Triggers>
I'm using SL5 and CM's SL5 assembly but no joy...
Interestingly, if I try to use 'ActionMessage' elsewhere it seems to be resolved correctly but of course it's not very useful outside of where I want it!
Update:
This is the view namespace def
xmlns:cal="http://www.caliburnproject.org"
I've tried the actual assembly qualified namespace and other combinations, all with the same issue
I've never had to use the ActionMessage syntax before, but as long as the control has an event that you're trying to attach to have you tried the following syntax:
<Button Content="Remove" cal:Message.Attach="[Event Click] = [Action Remove($dataContext)]" />
I've been able to use that on a wide variety of controls without any issues.
http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/17/caliburn-micro-soup-to-nuts-pt-3-all-about-actions.aspx
I had similar issues I had to add an extra xaml tag before calling ActionMessage my corresponding sample to get it to work was:
<i:Interaction.Triggers>
<Helpers:RoutedEventTrigger RoutedEvent="Helpers:DataChanging.Changing">
<cal:Action.Target>
<cal:ActionMessage MethodName="SelectedDataChanged">
<cal:Parameter Value="$eventargs"/>
</cal:ActionMessage>
</cal:Action.Target>
</Helpers:RoutedEventTrigger RoutedEvent="Helpers:DataChanging.Changing">
</i:Interaction.Triggers>

Triggering Silverlight Prism command with a keyboard shortcut

Does anybody know whether one can trigger prism command with a shortcut? What I mean is I want to be able to define binding of a command to keyboard shortcut in declarative manner, like ClientUI does:
Are there any opensource libraries for that purpose? Or maybe code samples?
I found this question but I don't think that it answers mine.
I've created such gesture trigger. And I'd like to share it with you guys. Basically, it is System.Windows.Interactivity trigger which can parse gestures represented as strings. Usage is as simple as in ClientUI:
<UserControl>
<i:Interaction.Triggers>
<behaviors:KeystrokeCommandTrigger Command="{Binding SaveChangesCommand}" Gesture="Ctrl+Shift+S" />
<behaviors:KeystrokeCommandTrigger Command="{Binding RejectChangesCommand}" Gesture="Ctrl+Shift+R" />
<behaviors:KeystrokeCommandTrigger Command="{Binding NewItemCommand}" Gesture="Ins" />
<behaviors:KeystrokeCommandTrigger Command="{Binding DeleteSelectedItemCommand}" Gesture="Del" />
<behaviors:KeystrokeCommandTrigger Command="{Binding UploadSomethingCommand}" Gesture="Ctrl+Shift+U" />
</i:Interaction.Triggers>
</UserControl>
The code is on pastie.
You could write an attached behavior that has a listens to the KeyUp event and then calls the Command. The complication comes in translating something like Gesture="Ctrl+Shift+A". You would need to write a parser to figure out exactly what key combination that string represents.

Categories

Resources