I'm trying to add a Blend behavior to a DatePicker control to bind an MVVM-Light RelayCommand to the DateChanged event like so:
<DatePicker Date="{Binding SelectedDate, Mode=TwoWay}">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="DateChanged">
<Core:InvokeCommandAction Command="{Binding DateChangedCommand, Mode=OneWay}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</DatePicker>
I'm using the following definitions:
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
However, I keep getting the following error:
WinRT information: Cannot add instance of type
'Microsoft.Xaml.Interactions.Core.EventTriggerBehavior' to a collection of type
'Microsoft.Xaml.Interactivity.BehaviorCollection'.
I have successfully used Blend behaviors in this way many other times in my project (and with other controls in the same Xaml file) to bind an event to a command, and the DatePicker control is the only one that has thrown an error. Is there another way to accomplish this or are WinRT DatePickers limited in this way?
Related
I'm creating a WPF app using MVVMLight.
I defined a ListView inside a TabControl DataTemplate, like so:
<TabControl.ContentTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding Builds}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
SelectedItem="{Binding SelectedBuild,
Mode=TwoWay}"
SelectionMode="Single">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding BuildSelectedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListView>
</DataTemplate>
</TabControl.ContentTemplate>
but XAML Designer returns this error (preventing the load of the designer preview):
XamlObjectWriterException: Collection property 'System.Windows.Controls.ListView'.'Triggers' is null.
at System.Xaml.XamlObjectWriter.WriteGetObject()
at System.Xaml.XamlWriter.WriteNode(XamlReader reader)
at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlReader templateReader, XamlObjectWriter currentWriter)
my Command is defined like so in my ViewModel:
private RelayCommand _buildSelectedCommand;
public RelayCommand BuildSelectedCommand => _buildSelectedCommand ??
(_buildSelectedCommand = new RelayCommand(BuildSelectedAction));
This is the first time I'm seeing this error, and it's happening only at design time, building and runtime it's fine.
Removing the i:Interaction.Triggers fix the problem, but I need the DoubleClick event on the list.
If you ask why I didn't add the trigger at the ListItem level, it's because I have to set a property on the ViewModel binding the TabControl Datatemplate, not the ListItem ViewModel.
Thanks a lot for the help!
I just verified that this is a Visual Studio 2015 bug, it doesn't repro in Visual Studio 2017 RC.
I am using Caliburn Micro for a Windows Phone app. I have a hyperlink control for which I want to bind the click event to my View Model. Below is the sample code
XAML, MyPage.xaml
<TextBlock>
<Run>Got to</Run>
<Hyperlink micro:Message.Attach="[Event Click] = [Action OpenAnotherPage]">
My Page</Hyperlink><Run Text="."></Run></TextBlock>
ViewModel MyPageViewModel.cs
public void OpenAnotherPage()
{
// some code
}
When I tap on the link, I get an exception
System.Exception: No target found for method
What could be the problem?
Update 1: Tried setting micro:Action.TargetWithoutContext="{Binding ElementName=MyPage, Path=DataContext}" on the Hyperlink control, but it didn't work
Give the TextBlock a name and use that as the ElementName since you have the Hyperlink nested into that control. Then Update1 should work.
Try following XAML (untested):
<Hyperlink>My Page
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ec:CallMethodAction TargetObject="{Binding}" MethodName="OpenAnotherPage" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Hyperlink>
The namespaces are following (you'll need to reference those 2 assemblies, they're by Microsoft and shipped with MS Expression Blend)
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ec="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
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.
Fairly new to Windows Phone and Xaml and I decided to start using the DataTemplates as it looked neater and I could easily switch them etc.
I have a requirement where on a button click depending on the data on the item in the list I want to call a different function or with different parameters. I thought the easiest way would be to bind a RoutedEventHandler to it via an anonymous function.
When I did this in code-behind with static controls on the formed it worked perfectly. It also worked when I added my own controls to a stack panel etc. But it was all quite messy.
// Example of RoutedEventHandler that works when I create the button in code behind
model.clickEventHandler = (s, e) => LoadResult(r.id);
<ScrollViewer Name="scrvResults" >
<ListBox Name="lbResults" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Command="{Binding clickEventHandler}" >
// Stuff
// Doesn't crash but doesn't fire the event
</Button>
<Button Click="{Binding clickEventHandler}" >
// Stuff
// Throws a com exception
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
I've tried various sub options. All the examples i've seen seem to link to a static function. Is this just some syntax i'm getting wrong is can I not bind to it this way?
You need to bind your command to a type of ICommand. See here for more info:
ICommand interface
Command Binding
Button click event can be bound by using interaction triggers, not by simply binding the event to the click attribute:
Using EventTrigger in XAML for MVVM – No Code Behind Code
I searched a lot through Google and StackOverflow, but nothing answered my problem.
I have two Xaml Files:
MainWindow.xaml
<Window x:Name="mainWindow">
<Window.DataContext>
<!-- Instantiate ViewModel of the MainWindow -->
<vm:MainWindowViewModel x:Name="viewModel"/>
</Window.DataContext>
<!-- Create the Menu of the MainWindow -->
<custom:MainMenu Grid.Row="0"/>
<ad:DockingManager x:Name="dockingManager">
<!-- ... -->
</Window>
And the MainMenu.xaml
<UserControl>
<Menu>
<MenuItem Header="{t:Translate MENU_LAYOUT_SAVE}" Command="{Binding SaveLayoutCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
<MenuItem Header="{t:Translate MENU_LAYOUT_LOAD}" Command="{Binding LoadLayoutCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
</Menu>
</UserControl>
And here my Problem occurs. Instead of passing the Mainwindow-object I want to pass the DockingManager x:Name="dockingManager" from MainWindow. But if i try to reference the object by its name it fails...
I tried the following Bindings:
CommandParameter="{Binding ElementName=dockingManager}"
CommandParameter="{Binding ElementName=dockingManager, RelativeSource={RelativeSource AncestorType=Window}}"
So how can I find and reference an Object (dockingManager) from the ElementTree within xaml. I want to avoid using extra code in Code-behind.
Try CommandParameter="{Binding ElementName=dockingManager, Path=.}".
EDIT:
The previous answer would not work. Here's a working idea...
In the Window.xaml:
<custom:MainMenu Grid.Row="0" Tag="{Binding ElementName=dockingManager}" />
In the MainMenu.xaml:
<UserControl x:Name="UcMainMenu" />
...
<MenuItem Header="{t:Translate MENU_LAYOUT_SAVE}" Command="{Binding SaveLayoutCommand}" CommandParameter="{Binding ElementName=UcMainMenu, Path=Tag}"/>
You can use:
CommandParameter="{x:Reference Name=yourElementName}"
Since you are using MVVM here is what you should do to come up with a slightly different solution:
Get rid of the CommandParameter
The command will trigger a callback in the MainWindowViewModel instance
This callback will change some state/properties in the MainWindowViewModel instance
The DockingManager instance reacts to that adjusted state of the MainWindowViewModel instance through bindings
The way you are doing it now is way too complicated. In addition to that, you are wildly mixing patterns here. MVVM tries to separate the business logic from the actual elements. You are using elements of MVVM with Smart UI/Code Behind techniques.
Also, consider using individual view models for individual controls. The main menu control is separate and the docking manager is, too. Why? Because you want to break everything into smaller pieces, but more importantly, because you might have reusability in mind. With the main menu trying to access a docking manager inside a Window that is not possible.