I'm getting a the following error when I use Interactivity:
Error Collection property 'System.Windows.Controls.Canvas'.'Triggers'
is null.
Here's my code:
<ItemsControl x:Name="StreamCanvasItemSource" ItemsSource="{Binding StreamCanvasItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="{Binding ActualWidth, ElementName=StreamImage}" Height="{Binding ActualHeight, ElementName=StreamImage}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas x:Name="StreamCanvas" Background="Transparent" Width="{Binding ActualWidth, ElementName=StreamImage}" Height="{Binding ActualHeight, ElementName=StreamImage}"
AuxiliaryUtils:SizeObserver.Observe="True" AuxiliaryUtils:SizeObserver.ObservedWidth="{Binding CurrentCanvasWidth, Mode=OneWayToSource}"
AuxiliaryUtils:SizeObserver.ObservedHeight="{Binding CurrentCanvasHeight, Mode=OneWayToSource}"
AuxiliaryUtils:SizeObserver.ObservedLeft="{Binding CanvasLeft, Mode=OneWayToSource}" AuxiliaryUtils:SizeObserver.ObservedTop="{Binding CanvasTop, Mode=OneWayToSource}">
<Interactivity:Interaction.Triggers>
<Interactivity:EventTrigger EventName="PreviewMouseWheel">
<Command:EventToCommand Command="{Binding OnMouseWheelCommand}" PassEventArgsToCommand="True" />
</Interactivity:EventTrigger>
<Interactivity:EventTrigger EventName="PreviewMouseDown">
<Interactivity:InvokeCommandAction Command="{Binding OnMouseDownCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Canvas}}}"/>
</Interactivity:EventTrigger>
<Interactivity:EventTrigger EventName="PreviewMouseMove">
<Interactivity:InvokeCommandAction Command="{Binding OnMouseMoveCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Canvas}}}"/>
</Interactivity:EventTrigger>
<Interactivity:EventTrigger EventName="PreviewMouseUp">
<Interactivity:InvokeCommandAction Command="{Binding OnMouseUpCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Canvas}}}"/>
</Interactivity:EventTrigger>
</Interactivity:Interaction.Triggers>
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
The thing is that everything works as expected when I run the program, I see the error when compiling, and I can't see the designer unless I comment the Interactivity block.
Any idea why?
How is the datacontext connected to the window/page? it would it advisable to add the following line to the window/page and setting IsDesignTimeCreatable to true:
d:DataContext="{d:DesignInstance Type=yourviewmodetype, IsDesignTimeCreatable=True}"
In this way the view will bind to the values of the viewmodel in designtime which is exactly what is going wrong atm in your application.
Related
I have a context menu which is binded to a list of items. When I click on an item, the command executes however I am having problems passing the selected item as a parameter, can anyone identify what I'm doing wrong?
I have tried passing {Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}} as the command parameter however it just gives me the whole list within the context menu and when. When I tried {Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MenuItem}}} no value was seen.
<ContextMenu x:Key="SelectFileTab" ItemsSource="{Binding ContextMenuItems}" x:Name="contextmenu">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding}">
</MenuItem>
</DataTemplate>
</ContextMenu.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseUp">
<i:InvokeCommandAction Command="{Binding SelectedFileToAdd, Mode=OneWay}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ContextMenu>
I really over complicated something quite simple, there was no need to use interaction.triggers issue to the command, all I needed to do was
<ContextMenu x:Key="SelectFileTab" ItemsSource="{Binding ContextMenuItems}" x:Name="contextmenu">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding}" Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.SelectedFileToAdd}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}}"/>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
I've got a ListView nested into another Listview. Now I want to bind an double-click event to the ListViewItems of the inner ListView
<UserControl>
<UserControl.Resources>
<DataTemplate x:Key="DefaultTemplate">
<ListView Name="jobsView" ItemsSource="{Binding jobs}" SelectedItem="{Binding Path=SelectedProduction}" >
<ListView.InputBindings>
<MouseBinding Gesture="LeftDoubleClick" Command="{Binding Path=DataContext.ItemSelectedCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" CommandParameter="{Binding ElementName=jobsView, Path=SelectedItem}" />
</ListView.InputBindings>
</ListView>
</DataTemplate>
</UserControl.Resources>
<ListView Name="weekView" ItemsSource="{Binding dayList}" ItemTemplate="{StaticResource DefaultTemplate}" >
</ListView>
</UserControl>
I created a RelayCommand called ItemSelectedCommand in my ViewModel.
public RelayCommand ItemSelectedCommand { get; private set; }
The RelayCommand is not getting triggered. I guess I'm setting the wrong RelativeSource. How would it look correct?
Where is your ListView inserted. Is there in a Visual Tree a parent with type of UserControl?
Also, what's quite good to fix Binding errors is to take a look at the Console. There should be Binding errors that might point you wherte is the mistake. Usually is writes down where it is trying to search for object and property :)
Also, I am not sure if private get; is actually allowed when binding to property.
<StackPanel Grid.Column="1">
<StackPanel.Resources>
<DataTemplate x:Key="DefaultTemplate" DataType="{x:Type sys:String}">
<StackPanel>
<TextBlock Text="{Binding .}"/>
<ListView>
<ListView.ItemsSource>
<CompositeCollection>
<sys:String>Sub Item</sys:String>
</CompositeCollection>
</ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}">
<TextBlock.InputBindings>
<MouseBinding Gesture="LeftDoubleClick" Command="{Binding DataContext.RenameCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}, PresentationTraceSources.TraceLevel=High}" CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}"/>
</TextBlock.InputBindings>
</TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</DataTemplate>
</StackPanel.Resources>
<ListView ItemTemplate="{StaticResource DefaultTemplate}">
<ListView.ItemsSource>
<CompositeCollection>
<sys:String> First Item</sys:String>
</CompositeCollection>
</ListView.ItemsSource>
</ListView>
</StackPanel>
Reason why it wasn't working for you is because the double Click was on an actual ListViewItem and NOT the ListView.
Okay, guys. I've been trying this for about 3 days now, and no amount of Googling is helping. Below is a snippet of my XAML (should be enough to follow along).
My problem is the command for the "ContextMenu".
As you can see I have DeleteTagCommand. Now that command works if I throw it in the position of CheckBoxCommand, which is great.. But it just will be called in it's current location, and it's driving me insane.
<ScrollViewer Grid.Column="0">
<StackPanel Orientation="Vertical">
<ItemsControl ItemsSource="{Binding Tags, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Value}" Margin="10,5,10,5" Command="{Binding DataContext.CheckBoxCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Grid}}}"
CommandParameter="{Binding }">
<CheckBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete" Command="{Binding DataContext.DeleteTagCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Grid}}}"
CommandParameter="{Binding}" />
</ContextMenu>
</CheckBox.ContextMenu>
</CheckBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
I've tried:
Calling 'ElementName' from all over the show, but it's never being picked up
Changing the 'AncestorLevel' to obscene numbers, hoping that was the problem
And more..
Not sure what would be useful for you guys, but below is the output message I get
Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.Grid', AncestorLevel='1''. BindingExpression:Path=DataContext.DeleteTagCommand; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'Command' (type 'ICommand')
Thanks
ContextMenus aren't actually part of the same visual tree as their parents so they can't directly bind to any elements within it. They can, however, still bind to StaticResources. The trick is to thus use an intermediate proxy such as the BindingProxy class shown on this page. Start by adding an instance to your ItemsControl resource block:
<ItemsControl.Resources>
<local:BindingProxy x:Key="Proxy" Data="{Binding}" />
</ItemsControl.Resources>
Then use it to bind your ContextMenu command:
<ContextMenu>
<MenuItem Header="Delete" Command="{Binding Data.DeleteTagCommand, Source={StaticResource Proxy}}" CommandParameter="{Binding}" />
</ContextMenu>
I want to write the event for list box from View Model. I try like this:-
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Gray" Padding="5" BorderThickness="1">
<StackPanel Orientation="Horizontal">
<Border BorderBrush="Wheat" BorderThickness="1">
<Image Name="ListPersonImage" Source="{Binding PersonImage}" Height="100" Width="100" Stretch="Uniform" Margin="10,0,0,0"/>
</Border>
<TextBlock Text="{Binding FirstName}" Name="firstName" Width="200" Foreground="White" Margin="10,10,0,0" FontWeight="SemiBold" FontSize="22" />
<Button DataContext="{Binding DataContext, ElementName=listBox1}" Command="{Binding addPerson}" Height="80" Width="80" >
<Button.Background>
<ImageBrush ImageSource="{Binding imagePath, Converter={StaticResource pathToImageConverter}}" Stretch="Fill" />
</Button.Background>
</Button>
</StackPanel>
</Border>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<i:InvokeCommandAction Command="{Binding ItemSelectedCommand,Mode=OneWay}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My ViewModel:-
public RelayCommand<MVVMListBoxModel> ItemSelectedCommand { get; private set; }
public MVVMListBoxViewModel()
{
ItemSelectedCommand = new RelayCommand<MVVMListBoxModel>(ItemSelected);
}
private void ItemSelected(MVVMListBoxModel myItem)
{
MessageBox.Show("Name==>" + myItem.FirstName);
//throw new NotImplementedException();
}
But nothing happening. Please let me know where I did mistake.
Thanks in advance.
Check output window to see if you got binding error. It seems that you got one, because you have ItemSelectedCommand defined in MVVMListBoxViewModel but ListBoxItem's DataContext is corresponding MVVMListBoxModel, so binding engine couldn't find the command.
Try to move definition of ItemSelectedCommand to MVVMListBoxModel and see if message box get displayed this way.
Do you want the trigger to be upon the SelectionChanged of the Listbox Item? Then the trigger should be outside the <ListBox.ItemTemplate> ... </ListBox.ItemTemplate>.
And the trigger should bind the CommandParamter to the SelectedItem
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<i:InvokeCommandAction Command="{Binding ItemSelectedCommand,Mode=OneWay}" CommandParameter="{Binding SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
I have the following user control
<ListBox ItemsSource="{Binding Persons}"
SelectedItem="{Binding SelectedPerson}"
VerticalAlignment="Top" Width="166" >
<ListBox.Template>
<ControlTemplate>
<StackPanel >
<ItemsPresenter/>
<Button Content="Add" Background="Transparent" Command="{Binding NewItemCommand}"/>
</StackPanel>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Height="16" Width="16" Background="Transparent" Command="{Binding DeleteItemCommand}">
<Image Source="images/delete-icon.png" />
</Button>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and i have a view model for it with two commands, the first command that you can see above NewItemCommand is working fine, how ever the second command DeleteItemCommand doesn't function.
is it because its in the item template?
Yes, this is because the DataContext for the ItemTemplate is the Item from Persons not the ViewModel
To bind the DeleteItemCommand on each item you will need to bind back to the ViewModel that is holding the command
Example, binding to the DataContext of the ListBox
<Button Command="{Binding Path=DataContext.DeleteItemCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}" />
Edit:
If you want to remove the item that the button was clicked on you can pass the item the button belongs to as the CommandParameter and handle that in your comman, Not sure what type of command you are using but this is simple if you are using RelayCommand or DelegateCommand
<Button Command="{Binding Path=DataContext.DeleteItemCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}"
CommandParameter="{Binding}" />
public MainWindow()
{
InitializeComponent();
DeleteItemCommand = new RelayCommand(person => DeletePerson(person as Person));
}
private void DeletePerson(Person person)
{
Collection.Remove(person);
}