access method from template in wpf - wpf

I'm using WPF with the caliburn micro framework to implement a MVVM pattern.
I've created a popup that gets filled with custom buttons inside a ListBox.
Now I want to call a method in my ViewModel when one of these buttons is clicked, but each approach I tried so far failed.
Here the code in comments works in the sense that it calls my method, but the parameter is always null.
<ListBox x:Name="lst" ItemsSource="{Binding OperatingModes}" ItemTemplate="{DynamicResource DataTemplate_Level1}" BorderThickness="0" ScrollViewer.CanContentScroll="False" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="3" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<!--<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown" >
<cal:ActionMessage MethodName="SelectMode">
<cal:Parameter Value="{Binding ElementName=lst, Path=SelectedItem}" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>-->
</ListBox>
And this is the Template I'm using. Whenever I call this method, I'm getting "No target found for method SelectMode." As you can see, I've tried different aproaches, although I'm not sure that I used the TargetWithoutContext call properly.
As far as I can tell I need to somehow bind my template to the data context of the "normal" xaml code, but I failed so far. How do I access my method properly?
<DataTemplate x:Key="DataTemplate_Level1" x:Name="myListTemplate" >
<ListBox ItemsSource="{Binding}" BorderThickness="0" ScrollViewer.CanContentScroll="False" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" cal:Bind.Model="{Binding}" cal:Action.TargetWithoutContext="{Binding DataContext, ElementName=lst}">
<Button Style="{StaticResource InformButton}" Content="{Binding Path=Name}" FontSize="11" BorderBrush="BlueViolet" cal:Message.Attach="SelectMode($dataContext)">
<!--<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseRightButtonDown" >
<cal:ActionMessage MethodName="SelectMode">
<cal:Parameter Value="{Binding ElementName=myListTemplate, Path=SelectedItem.Name}" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>-->
</Button>
</StackPanel>
</ListBox>
</DataTemplate>

Related

Executing the Button's Command on ListBoxItem Selection

I have this (simplified for SO) listbox:
<ListBox x:Name="CurriculumList"
ItemsSource="{Binding FilteredCurriculums}"
SelectedIndex="0"
SelectionMode="Single"
IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Name="TheButton"
HorizontalContentAlignment="Stretch"
Content="{Binding DisplayMember}"
CommandParameter="{Binding Id}"
Command="{Binding OpenCurriculumEditViewCommand}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I can navigate up and down the listBoxItems with the keyboard to change selection, but it doesn't change the detail view - the Button in the DataTemplate doesn't actually get clicked, so the OpenCurriculumEditViewCommandnever gets executed.
Anyone have any idea how I can do this?
Well, if you want to execute OpenCurriculumEditViewCommand when the ListBox selection changes, you could do the following:
First:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
And then..
<ListBox x:Name="CurriculumList"
ItemsSource="{Binding FilteredCurriculums}"
SelectedIndex="0"
SelectionMode="Single"
IsSynchronizedWithCurrentItem="True">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction CommandParameter="{Binding Path=SelectedItem.Id, RelativeSource={RelativeSource AncestorType=ListBox}}" Command="{Binding OpenCurriculumEditViewCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
You should not use a Button at all if you want it to trigger on selection.

WPF Textboxes and Textblocks not rendered

I have a strange behavior of my application on some computers (it only happens at some customer pcs, i can't reproduce it on my machines).
I have an application to enter and view production scrap data. Every column is an control on it's own. The Expanders are accordion Controls from the WPF Toolkit.
Sometimes Textblocks are not visible:
When the bug happens to Textboxes, they are not even consuming any space:
This is the Datatemplate for the Content of the Accordion Item:
<DataTemplate x:Key="YieldAccContent" DataType="Models:Cell">
<DataTemplate.Resources>
<DataTemplate x:Key="It1">
<StackPanel >
<Label BorderBrush="{x:Static SystemColors.ControlLightBrush}" Padding="1" Height="22" BorderThickness="1" Content="{Binding Value}" Visibility="{Binding Cell.CellGroup.ParentMeasurement.IsEnabled, Converter ={StaticResource boolTovisinv}}"/>
<controls:NumberTextbox Text="{Binding Value, Converter ={StaticResource EmptyStringToNullConverter}, UpdateSourceTrigger=PropertyChanged}" Height="22" Width="80" Visibility="{Binding IsEnabledAndBad, Converter ={StaticResource boolTovis}}" Background="AliceBlue">
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus" >
<cmd:EventToCommand Command="{Binding MeasurmentViewModel.LostFocusCommand, Mode=TwoWay, Source={StaticResource Locator}}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</controls:NumberTextbox>
<toolkit:MaskedTextBox Mask ="-99999999" Value="{Binding Value, Converter ={StaticResource EmptyStringToNullConverter}, UpdateSourceTrigger=PropertyChanged}" PromptChar=" " Height="22" Width="80" Visibility="{Binding IsEnabledAndGood, Converter ={StaticResource boolTovis}}" IncludeLiterals="True" IncludePrompt="False" Background="AliceBlue" ValueType="{x:Type sys:Int64}" GotFocus="MaskedTextBox_GotFocus_1" SelectionChanged="MaskedTextBox_SelectionChanged_1">
</toolkit:MaskedTextBox>
</StackPanel>
</DataTemplate>
</DataTemplate.Resources>
<StackPanel >
<Label BorderBrush="{x:Static SystemColors.ControlLightBrush}" BorderThickness="1" Padding="1" Height="22" Width="160" Content="{Binding YieldInput}" Background="Moccasin"/>
<Label BorderBrush="{x:Static SystemColors.ControlLightBrush}" BorderThickness="1" Padding="1" Height="22" Width="160" Content="{Binding YieldOutput}" Background="Moccasin"/>
<Label BorderBrush="{x:Static SystemColors.ControlLightBrush}" BorderThickness="1" Padding="1" Height="22" Width="160" Content="{Binding Yield}" Background="Moccasin"/>
<ItemsControl ItemsSource="{Binding Stations}" ItemTemplate="{StaticResource It1}">
</ItemsControl>
</StackPanel>
</DataTemplate>
This is the Accordion Item itself:
<System_Windows_Controls:Accordion ContentTemplate="{StaticResource Cont}" ItemTemplate="{StaticResource Head}" ItemsSource="{Binding Cells}" SelectedIndex="{Binding SelectedAccItem, Mode=TwoWay}" SelectionMode="{Binding MeasurmentViewModel.SelectionMode, Source={StaticResource Locator}}" HorizontalAlignment="Stretch" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemsChanged" >
<cmd:EventToCommand Command="{Binding MeasurmentViewModel.SelectedItemsChangedCommand, Mode=TwoWay, Source={StaticResource Locator}}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</System_Windows_Controls:Accordion>
What could be the cause of this behavior?
Going by your description about the missing TextBoxes not taking any space, I can only assume that you have a Trigger or Converter attached to their Visibility property. If you put a break point in the Converter that is attached to the offending TextBox, then you can debug whether this is the cause quite easily. I assume that the bool value(s) that you are binding to in the Visibility property is not being set correctly... please check whether this is true.

EventToCommand in ItemControl in Windows Phone 8

I cannot understand why I cant call eventToCommand in my datatemplate inside ItemControl. According to this post I should implement it in the dataTemplate, but the command is never invoked. This is the eventToCommand im trying to insert in my code.
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<cmd:EventToCommand Command="{Binding ItemSelectedCommand, Mode=OneWay}"
PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
And this is the code im trying to instert it to. However, as the comments say, it is never invoked when put in the dataTemplete. The problem is not the viewModel, the command works in the panelTemplate.
<ItemsControl ItemsSource="{Binding GroupRow1}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
<!-- COMMAND WORKS HERE, but cannot locate which item has been pressed -->
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="#FF1756C3" Height="173" Width="173" Margin="12,0,0,0" >
<!-- COMMAND DOES NOT WORK HERE?!?! -->
<StackPanel>
<TextBlock Text="{Binding LineOne}" /> <!-- These bindings work -->
<TextBlock Text="{Binding LineTwo}" />
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
How do I find out which Item has been pressed?
Many answers, but none of them worked for me. I redesigned my solution and got rid of the eventtocommand which wasent working. Instead I made buttons with custom content to look the same as my border.
Simpler code and a better solution.
<ItemsControl ItemsSource="{Binding GroupRow1}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button CommandParameter="{Binding LineOne}" Height="195" Width="195" Margin="0,0,-10,0" Click="Button_Click_2" Background="#FF1756C3">
<StackPanel>
<TextBlock Text="{Binding LineOne}" />
<TextBlock Text="{Binding LineTwo}" />
</StackPanel>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I had a similar problem before, what solved it for me was referencing the VM in the binding. Try to set PassEventArgsToCommand to false if you want to receive the item instead of the EventArgs
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<cmd:EventToCommand PassEventArgsToCommand="False"
CommandParameter="{Binding}"
Command="{Binding Path=VM_Name_Here.Command_Name_Here, Source={StaticResource Locator}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
Edit- If you are using MVVM Light, in the app.xml you should have something like:
xmlns:vm="clr-namespace:PhoneApplication.ViewModel (namespace where your ViewModelLocator is under)
<vm:ViewModelLocator x:Key="Locator"
d:IsDataSource="true" />
You are telling the binding to look in the ViewModelLocator for a particular VM.
Hope it helps,
Regards.
I think it has to do with your binding in the data template. How is the view created? I think the command is a property of the viewModel, not GroupRow1 which is the collection for your items control. You need to bind to the command in your ViewModel. SO if your view is a usercontrol, the following should work. (if its of another type then change the ancestortype)
<cmd:EventToCommand Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}},Path=DataContext.ItemSelectedCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TextBlock}},Path=Name}"/>
The command parameter adds the name of the textblock for example, you could change that to any property of the textblock.
I would personally have SelectedItem property in my viewmodel that can be accesses as an object from the ItemSelectCommand
Hope this helps.
The answer is pretty obvious. In ItemsPanelTemplate your binding source is still the ViewModel and your command stays at your ViewModel. But in DataTemplate you are iterating over GroupRow1 items and your binding source is individual item. If you want to use your command there, you have to bind from the relative source in example:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<cmd:EventToCommand Command="{Binding ViewModel.ItemSelectedCommand, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=OneWay}"
PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>

Interaction.Triggers fail in MVVM listbox view

The xaml below works correctly when I click (MouseDown) anywhere on the background of the listbox. The problem is that I can not get it to work when I click on any single item in the listbox. I've tried putting the trigger code inside the border, image or TextBlock with no success.
<ListBox Name="SelectL2List" ItemsSource="{Binding L2Items, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsSynchronizedWithCurrentItem="True">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<si:CallDataMethod Method="HideSelectL2View" Target="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type ViewModels:MediaItemViewModel}" >
<Border BorderThickness="1,1,3,3" Margin="10" CornerRadius="3">
<StackPanel Orientation="Horizontal" >
<Image Source="{Binding Image}"/>
<TextBlock Text="{Binding L2Title}" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Any help would be appreciated.
You have to make sure that things are hit testing as well, you can set the Background of the Border to Transparent to ensure that.
Also the mouse events are intercepted by the ListBoxItems, use the tunneling versions, i.e. PreviewMouseDown.

mvvm light PassEventArgsToCommand break app in ListBoxDragDropTarget

Hi I'm trying to pass eventargs to comman that I bind in ViewModel. Everything works fine if I don't use PassEventArgsToCommand="True". But If put PassEventArgsToCommand="True" than app break. Did you have similar problem?
<Controls:ListBoxDragDropTarget Grid.Column="1" AllowDrop="true" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Drop">
<GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding PersonDrop, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox x:Name="fromListBox" ItemsSource="{Binding Person, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name, Mode=TwoWay}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Controls:ListBoxDragDropTarget>
Ok. I found out. I used System.Windows.DragEventArgs instead of Microsoft.Windows.DragEventArgs as argument in my command.

Resources