ListboxItem self binding - c#

How can i bind a command parameter to self?
I try like this:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Button Content="G"
Background="Green"
Foreground="White"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}},
Path=DataContext.LabelGoodCommand}"
CommandParameter="{Binding /}"
Width="20" Height="20" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
But this doesn't work.
In viewmodel listbox items binding to ObservableCollection.

CommandParameter="{Binding RelativeSource={x:Static RelativeSource.Self}}"
By this you can get the Control and in your Execute method, Use as like this,
if(pram is Button)
{
var model = ((Button)pram).DataContext;
}
you can get the Model here.
OR
<Button Content="G"
Background="Green"
Foreground="White"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}},
Path=DataContext.LabelGoodCommand}"
CommandParameter="{TemplateBinding DataContext}"
Width="20" Height="20" />
OR
<Button Content="G"
Background="Green"
Foreground="White"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}},
Path=DataContext.LabelGoodCommand}"
CommandParameter="{Binding DataContext,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}"
Width="20" Height="20" />

If by "self", you mean the button, you can do that:
CommandParameter="{Binding RelativeSource={x:Static RelativeSource.Self}}"
If you want the current DataContext, just don't specify the path:
CommandParameter="{Binding}"

Related

Why ContextMenu Command and CommandParameter are not working in DataGrid

I have a DataGird, then it's include Expander and ContextMenu.
This DataGird is grouping. And, it's has different ContextMenu between Expander and DataGridItem.
However, I want to binding MenuItem Command to my command, and pass DataGird's SelectedItems or SelectedIndex to Command.
But this command is not invoked. Even if it work, the parameter is not pass when I survey some method got goal (like set property tag).
So, I want to know what's correct method.
General
<UserControl.DataContext>
<vm:ViewModel x:Name="VM"/>
</UserControl.DataContext>
<Grid>
<DataGrid x:Name="dg"
ItemsSource="{Binding SourceData}"
AutoGenerateColumns="False"
CanUserResizeColumns="False"
CanUserResizeRows="False"
CanUserAddRows="False"
CanUserSortColumns="False"
SelectionMode="Extended"
RowHeaderWidth="0"
GridLinesVisibility="Horizontal">
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="BorderThickness" Value="0"/>
<!-- Remove the focus indication for the selected cell -->
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
</Style>
</DataGrid.CellStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="No." Binding="{Binding No}" />
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
</DataGrid.Columns>
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="False" MouseRightButtonDown="Expander_MouseRightButtonDown" ButtonBase.Click="Expander_Click">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="Insert" InputGestureText="Ctrl+I" Command="{Binding InsertGroupItems"/>
<MenuItem Header="Remove" InputGestureText="Ctrl+D" Command="{Binding RemoveGroupItems"/>
</ContextMenu>
</StackPanel.ContextMenu>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding ItemCount}"/>
<TextBlock Text=" item(s)"/>
</StackPanel>
</Expander.Header>
<ItemsPresenter>
<ItemsPresenter.ContextMenu>
<ContextMenu>
<ContextMenu>
<MenuItem Header="Insert" InputGestureText="Ctrl+I" Command="{Binding InsertSelectedItems" CommandParameter="{Binding ElementName=dg, Path=SelectedIndex}"/>
<MenuItem Header="Remove" InputGestureText="Ctrl+D" Command="{Binding RemoveSelectedItems" CommandParameter="{Binding ElementName=dg, Path=SelectedItems}"/>
</ContextMenu>
</ItemsPresenter.ContextMenu>
</ItemsPresenter>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
</Grid>
This work to invoke command, but can't pass parameter
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Tag" Value="{Binding DataContext, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Insert" InputGestureText="Ctrl+I" Command="{Binding PlacementTarget.Tag.InsertSelectedItems, RelativeSource={RelativeSource AncestorType=ContextMenu}}" CommandParameter="{Binding ElementName=dg, Path=SelectedIndex}"/>
<MenuItem Header="Remove" InputGestureText="Ctrl+D" Command="{Binding PlacementTarget.Tag.RemoveSelectedItems, RelativeSource={RelativeSource AncestorType=ContextMenu}}" CommandParameter="{Binding ElementName=dg, Path=SelectedItems}"/>
</ContextMenu>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="False" MouseRightButtonDown="Expander_MouseRightButtonDown" ButtonBase.Click="Expander_Click">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="Insert" InputGestureText="Ctrl+I" Command="{Binding InsertGroupItems}"/>
<MenuItem Header="Remove" InputGestureText="Ctrl+D" Command="{Binding RemoveGroupItems}"/>
</ContextMenu>
</StackPanel.ContextMenu>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding ItemCount}"/>
<TextBlock Text=" item(s)"/>
</StackPanel>
</Expander.Header>
<ItemsPresenter/>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
BTW, how to cast SelectedItems when got parameter?
It's not work
private void Excute(object parameter)
{
IList list = parameter as IList;
foreach (var item in list)
{
Remove((Data)item);
}
}
So, maybe I have three problems.
The ContextMenu not working.
The CommandParameter not passing.
How to convert SelectedItems to a list?
Thanks!
A MenuItem in a ContextMenu can't use an ElementName to bind to the DataGrid because the ContextMenu and the DataGrid belong to different element trees.
What you could do is to bind the Tag property of the ItemsPresenter to the DataGrid and then bind to properties of the DataGrid through the PlacementTarget of the ContextMenu:
<ItemsPresenter Tag="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}}">
<ItemsPresenter.ContextMenu>
<ContextMenu>
<MenuItem Header="Insert2" InputGestureText="Ctrl+I"
DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
Command="{Binding DataContext.InsertSelectedItems}"
CommandParameter="{Binding SelectedIndex}"/>
<MenuItem Header="Remove2" InputGestureText="Ctrl+D"
DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
Command="{Binding DataContext.RemoveSelectedItems}"
CommandParameter="{Binding SelectedItems}"/>
</ContextMenu>
</ItemsPresenter.ContextMenu>
</ItemsPresenter>
How to convert SelectedItems to a list?
Like you are doing. This should work provided that the binding to the SelectedItems property of the DataGrid works:
private void Execute(object parameter)
{
IList list = parameter as IList;
foreach (var item in list)
{
Remove((Data)item);
}
}
Edit:
Of course you cannot use ElementName when binding to the CommandArgument either. Try this:
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Tag" Value="{Binding Path=., RelativeSource={RelativeSource AncestorType=DataGrid}}" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Insert" InputGestureText="Ctrl+I"
Command="{Binding PlacementTarget.Tag.DataContext.InsertSelectedItems, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding PlacementTarget.Tag.SelectedIndex, RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
<MenuItem Header="Remove" InputGestureText="Ctrl+D"
Command="{Binding PlacementTarget.Tag.DataContext.RemoveSelectedItems, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding PlacementTarget.Tag.SelectedItems, RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
</ContextMenu>
</Setter.Value>
</Setter>

Binding ContextMenu DataContext works with TextBlock but not with TextBox

I got this in my view, I need to be able to edit the name of the Skeleton items in the TreeView via right-click -> context menu -> rename. There is a slight problem:
When I use TextBlock it works fine (TextBlock is not editable) but the binding shuts down when I use TextBox. I tried several bindings and ancestor types, to no avail. Not sure if I should switch to TextBox at all.
<UserControl.Resources>
<Image x:Key="visibilityImage" Source="../Resources/visibility.png" Height="16" Width="16" />
<Image x:Key="visibilityOffImage" Source="../Resources/visibilityoff.png" Height="16" Width="16" />
<Style TargetType="{x:Type ToggleButton}" x:Key="visibilityButtonStyle">
<Setter Property="Content" Value="{DynamicResource visibilityImage}" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="{DynamicResource visibilityOffImage}" />
</Trigger>
</Style.Triggers>
</Style>
<DataTemplate DataType="{x:Type commonVM:GyroSuitViewModel}">
<views:GyroSuitView></views:GyroSuitView>
</DataTemplate>
<DataTemplate DataType="{x:Type commonVM:SkeletonViewModel}">
<views:SkeletonView></views:SkeletonView>
</DataTemplate>
</UserControl.Resources>
<Grid Name="Root">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<StackPanel Orientation="Vertical">
<Label Content="{Binding Title}" Margin="2"/>
<TreeView Name="SkeletonItems" ItemsSource="{Binding Skeletons}" commonExtensions:RightClickTreeViewSelectionExtension.IsEnabled="True">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True"/>
<Setter Property="Foreground" Value="{StaticResource ForegroundBrush}"/>
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
<Style.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="Grid.ColumnSpan" Value="2" />
</Style>
</Style.Resources>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Records}">
<DockPanel LastChildFill="True">
<ToggleButton Background="Transparent" BorderThickness="0" Width="20" Height="20" IsChecked="{Binding IsVisible, Mode=TwoWay}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding ChangeVisibilityCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding ChangeVisibilityCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Image Stretch="Fill" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="true">
<Setter Property="Source" Value="../Resources/visibility.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsVisible}" Value="false">
<Setter Property="Source" Value="../Resources/visibilityoff.png"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ToggleButton>
<ToggleButton Visibility="{Binding RecordingButtonVisibility}" Background="Transparent" BorderThickness="0" Width="20" Height="20" IsChecked="{Binding IsRecording, Mode=TwoWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding RecordCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding RecordCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Image Stretch="Fill" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsRecording}" Value="true">
<Setter Property="Source" Value="../Resources/stop.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsRecording}" Value="false">
<Setter Property="Source" Value="../Resources/record.png"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ToggleButton>
<Button Visibility="{Binding DeleteButtonVisibility}" Name="DeleteButton" Height="20" BorderThickness="0" Command="{Binding DeleteCommand}" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Image Source="../Resources/delete.png" Stretch="Fill"/>
</Button>
<xctk:ColorPicker SelectedColor="{Binding SkeletonColor, Converter={converter:DrawingColorToMediaColorConverter}}" BorderThickness="0" Margin="2" StandardColors="{Binding ElementName=Root, Path=DataContext.AvailableSkeletonColors}" Background="Transparent" Width="20" ShowAdvancedButton="False" ShowAvailableColors="False" ShowDropDownButton="False" ShowStandardColors="True" StandardColorsHeader="" />
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" Tag="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext}">
<TextBlock.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}" Visibility="{Binding Path=ContextMenuVisibility}">
<MenuItem Header="Rename"/>
<MenuItem Header="Open Containing Folder" Command="{Binding OpenFolderCommand}"/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</DockPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<ContentPresenter Name="details" Content="{Binding SelectedItem, ElementName=SkeletonItems}" />
</StackPanel>
</ScrollViewer>
</Grid>
When I use the TextBox these are the errors in the output:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=Root'. BindingExpression:Path=DataContext.AvailableSkeletonColors; DataItem=null; target element is 'ColorPicker' (Name=''); target property is 'StandardColors' (type 'ObservableCollection`1')
and
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.UserControl', AncestorLevel='1''. BindingExpression:Path=DataContext; DataItem=null; target element is 'TextBox' (Name=''); target property is 'Tag' (type 'Object')
Thanks for every input!

Flip flyout closebutton around without changing position

I'm trying to flip the arrow to point to the other direction in my flyout without changing the Position to left.
Right now this is how I'm creating my flyout
<Controls:Flyout Name="New_Flyout"
Header="Select Account Type"
IsOpen="False"
Theme="Light"
Position="Right"
HorizontalContentAlignment="Left"
HorizontalAlignment="Left"
Margin="0,0,0,0"
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Controls:MetroWindow}, Path=ActualWidth}"
AnimateOpacity="True"
AnimateOnPositionChange="True"
>
Add a new Trigger to the default HeaderTemplate:
<DataTemplate x:Key="HeaderTemplate1"
x:Shared="False">
<DockPanel x:Name="dpHeader"
Margin="10,25,10,10"
VerticalAlignment="Center"
LastChildFill="True">
<Button x:Name="nav"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Controls:Flyout}}, Path=CloseCommand, Mode=OneWay}"
DockPanel.Dock="Left"
Style="{DynamicResource MetroCircleButtonStyle}"
Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Controls:Flyout}}, Path=CloseButtonVisibility}"
Height="40"
Width="40"
FontFamily="Segoe UI Symbol"
Foreground="{Binding RelativeSource={RelativeSource AncestorType={x:Type Controls:Flyout}}, Path=Foreground}"
FontSize="16"
VerticalAlignment="Bottom">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<Actions:SetFlyoutOpenAction TargetObject="{Binding RelativeSource={RelativeSource AncestorType={x:Type Controls:Flyout}}}"
Value="False" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Rectangle Width="20"
Height="15"
Fill="{Binding RelativeSource={RelativeSource AncestorType={x:Type Controls:Flyout}}, Path=Foreground}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill">
<VisualBrush.Visual>
<Canvas Width="48"
Height="48"
Clip="F1 M 0,0L 48,0L 48,48L 0,48L 0,0"
UseLayoutRounding="False">
<Path Width="25"
Height="18"
Canvas.Left="12"
Canvas.Top="15"
Stretch="Fill"
Fill="Black"
Data="F1 M 12,22L 12,26L 28.25,26L 21,33L 27.5,33L 37,24L 27.5,15L 21,15L 28.25,22L 12,22 Z " />
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
</Rectangle.OpacityMask>
</Rectangle>
</Button>
<TextBlock Text="{Binding}"
x:Name="PART_BackButton"
Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Controls:Flyout}}, Path=TitleVisibility}"
FontSize="{StaticResource FlyoutHeaderFontSize}"
Margin="15,0,0,0"
VerticalAlignment="Center" />
</DockPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Position, RelativeSource={RelativeSource AncestorType={x:Type Controls:Flyout}}}"
Value="Right">
<Setter TargetName="nav"
Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="45" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Position, RelativeSource={RelativeSource AncestorType={x:Type Controls:Flyout}}}"
Value="Left">
<Setter TargetName="nav"
Property="DockPanel.Dock"
Value="Right" />
<Setter TargetName="PART_BackButton"
Property="TextAlignment"
Value="Right" />
<Setter TargetName="PART_BackButton"
Property="Margin"
Value="0,0,15,0" />
<Setter TargetName="nav"
Property="LayoutTransform">
<Setter.Value>
<ScaleTransform ScaleX="-1" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Position, RelativeSource={RelativeSource AncestorType={x:Type Controls:Flyout}}}"
Value="Top">
<Setter TargetName="dpHeader"
Property="Margin"
Value="10" />
<Setter TargetName="nav"
Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="-90" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Position, RelativeSource={RelativeSource AncestorType={x:Type Controls:Flyout}}}"
Value="Bottom">
<Setter TargetName="dpHeader"
Property="Margin"
Value="10" />
<Setter TargetName="nav"
Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="90" />
</Setter.Value>
</Setter>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
And then apply it to your Flyout:
<Controls:Flyout Name="New_Flyout"
HeaderTemplate="{StaticResource HeaderTemplate1}"
Header="Select Account Type"
IsOpen="False"
Theme="Dark"
Position="Right"
HorizontalContentAlignment="Left"
HorizontalAlignment="Left"
Margin="0,0,0,0"
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Controls:MetroWindow}, Path=ActualWidth}"
AnimateOnPositionChange="True">
I used 45 degrees just to make it clear, but for your purposes you want to use 180:

ContextMenu as staticresource issues

I've been scratching my head for a while at an issue i was having, eventually tracked it down to a problem with contextmenu's as a static resource.
The problem i'm having is that when i moved the contextmenu into a static resource, and used datatriggers to load a context menu based on the state of an object, the button commands seemed to get stuck on the datacontext bound on the first load, but the other binding's worked fine.
What i have is the following, a view which contains a listview using a custom item template, this item template is:
<DataTemplate x:Key="appListTemplate">
<Button cal:Message.Attach="Run" HorizontalAlignment="Stretch" VerticalAlignment="Center">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="#BBF7F7F7"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Height="50" HorizontalAlignment="Stretch" Background="{TemplateBinding Background}">
<Border CornerRadius="5" Height="35" Width="35" Background="SkyBlue" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10,0,0,0"/>
<Label Content="{Binding AppName}" ToolTip="{Binding AppStatus}" VerticalAlignment="Center" Margin="50,0,0,0" FontSize="16"/>
<Image Source="{Binding Icon}" ToolTip="{Binding AppIconName}" Stretch="UniformToFill" Height="20" Width="20" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,15,0"/>
<StackPanel VerticalAlignment="Top">
<Line Stroke="#FFCDCDCD" Stretch="Fill" X2="1" />
<Line Stroke="#FFEAEAEA" Stretch="Fill" X2="1" />
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding AppStatus}" Value="{x:Static enum:AppStatus.DISABLED}">
<Setter Property="IsEnabled" Value="False"/>
<Setter Property="Background" Value="Lime"/>
</DataTrigger>
<DataTrigger Binding="{Binding AppStatus}" Value="{x:Static enum:AppStatus.NOACCESS}">
<Setter Property="Opacity" Value="0.5"/>
<Setter Property="ContextMenu" Value="{StaticResource ResourceKey=NoAccessContextMenu}" />
</DataTrigger>
<DataTrigger Binding="{Binding AppStatus}" Value="{x:Static enum:AppStatus.INSTALLED}">
<Setter Property="ContextMenu" Value="{StaticResource ResourceKey=InstalledContextMenu}"/>
</DataTrigger>
<DataTrigger Binding="{Binding AppStatus}" Value="{x:Static enum:AppStatus.NOTINSTALLED}">
<Setter Property="ContextMenu" Value="{StaticResource ResourceKey=UninstalledContextMenu}"/>
</DataTrigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#FFF7F7F7"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
As you can see, depending on the status there is a different contextmenu loaded. these are defined as:
<ContextMenu x:Key="InstalledContextMenu" StaysOpen="False">
<MenuItem Header="{Binding AppName}" HorizontalContentAlignment="Right" FontWeight="Bold" IsEnabled="False"/>
<Separator/>
<MenuItem x:Name="RunApplication" Header="Run" cal:Message.Attach="Run"/>
<MenuItem Header="Uninstall" cal:Message.Attach="Uninstall"/>
</ContextMenu>
<ContextMenu x:Key="UninstalledContextMenu" StaysOpen="False">
<MenuItem Header="{Binding AppName}" HorizontalContentAlignment="Right" FontWeight="Bold" IsEnabled="False"/>
<Separator/>
<MenuItem x:Name="Install" Header="Install" cal:Message.Attach="Install"/>
</ContextMenu>
<ContextMenu x:Key="NoAccessContextMenu" StaysOpen="False">
<MenuItem Header="{Binding AppName}" HorizontalContentAlignment="Right" FontWeight="Bold" IsEnabled="False"/>
<Separator/>
<MenuItem x:Name="RequestAccess" Header="Request Access" cal:Message.Attach="RequestAccess"/>
</ContextMenu>
The problem comes when you right click the first item in the list, it displays the options correctly E.G
SHIPPING
--------
Run
Uninstall
This work's 100%, however when you then right click on the second item in the list you get the following:
PROJECTS
--------
Run
Uninstall
as you can see, the appname binding updates fine, however when you click uninstall, it calls the uninstall method on the shipping VM, when it should be calling the uninstall on the projects VM. This will continue to happen with every item calling the methods on Shipping VM instead.
I'm at a total loss on what i can do about this, or even why it's happening. Any help would be most welcome.
Ok, Thanks to some hints from people, i've eventually tracked this down.
The issue is caused because the contextmenu is not the in visual tree, and microsofts "fix" is to make the contextmenu inherit it's parents datacontext, however this only ever happens once, and obviously when changing the datacontext, such as when changing selected item in a listview, the datacontext is never updated.
To solve this, i changed the contextmenu to the following.
<ContextMenu x:Key="InstalledContextMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}" StaysOpen="False">
<MenuItem Header="{Binding AppName}" HorizontalContentAlignment="Right" FontWeight="Bold" IsEnabled="False"/>
<Separator/>
<MenuItem x:Name="RunApplication" Header="Run" cal:Action.TargetWithoutContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu}}" cal:Message.Attach="Run"/>
<MenuItem Header="Uninstall" cal:Action.TargetWithoutContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu}}" cal:Message.Attach="Uninstall"/>
</ContextMenu>
<ContextMenu x:Key="UninstalledContextMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}" StaysOpen="False">
<MenuItem Header="{Binding AppName}" HorizontalContentAlignment="Right" FontWeight="Bold" IsEnabled="False"/>
<Separator/>
<MenuItem x:Name="Install" cal:Action.TargetWithoutContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu}}" Header="Install" cal:Message.Attach="Run"/>
</ContextMenu>
<ContextMenu x:Key="NoAccessContextMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}" StaysOpen="False">
<MenuItem Header="{Binding AppName}" HorizontalContentAlignment="Right" FontWeight="Bold" IsEnabled="False"/>
<Separator/>
<MenuItem x:Name="RequestAccess" cal:Action.TargetWithoutContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu}}" Header="Request Access" cal:Message.Attach="RequestAccess"/>
</ContextMenu>
As you can see, i now create my own binding for the datacontext and then setup the target context for my caliburn micro actions on each menuitem. It's a bit of an arse having to do this for each menu item, but seems to be the simplest fix.

wpf CheckBox Command in a DataTemplate

I have a DataTemplate like this:
<DataTemplate x:Key="CheckBoxDataTemplate">
<CheckBox IsChecked="{Binding
Path=IsSelected, Mode=TwoWay}"
HorizontalAlignment="Center"
VerticalAlignment="Center" Name="aDM_LEVEL_FIELDListView" Path="SelectedItem">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<WPFCtlr:EventToCommand Command="{Binding DataContext.UnCheckCommand, RelativeSource={RelativeSource FindAncestor,ListView,1}}" CommandParameter="{Binding ElementName=_thisChk}" />
<!--<i:InvokeCommandAction Command="{Binding Path=SelectItemRelayCommand}" />-->
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
<!--Command="{Binding Path=DataContext.UnCheckCommand}"
CommandParameter="{Binding Path=IsChecked, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />-->
</DataTemplate>
This is the templateSelector:
<TemplateSelector:PropertyDataTemplateSelector x:Key="templateSelector"
BooleanDataTemplate="{StaticResource CheckBoxDataTemplate}"
IsEnum="IsExclusive"/>
And this is the ListView where the template is referenced:
<ListView Grid.Row="1"
ItemsSource="{Binding Path=FilteredLevelFields}"
Margin="5,10,5,5"
Name="aDM_LEVEL_FIELDListView"
SelectionMode="Single"
FontSize="13"
Background="AliceBlue"
BorderBrush="AliceBlue"
SelectedItem="{Binding Path=CurrentElement}">
<!--Style of items-->
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<!--Properties-->
<Setter Property="Control.HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Control.VerticalContentAlignment" Value="Center" />
<!--Trigger-->
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource GridViewColumnHiddenHeaderStyle}">
<GridViewColumn Header="ID LEVEL FIELD" CellTemplate="{StaticResource FatherTemplate}" Width="300"/>
<GridViewColumn Header="Value" CellTemplateSelector="{StaticResource templateSelector}" Width="80" />
<GridViewColumn Header="ID LEVEL FIELD" CellTemplate="{StaticResource DetailIdenTemplate}" Width="300"/>
</GridView>
</ListView.View>
</ListView>
This is the command in my ViewModel:
RelayCommand _unCheckCommand;
public ICommand UnCheckCommand
{
get
{
if (_unCheckCommand == null)
{
_unCheckCommand = new RelayCommand(
param => this.UnCheck(param),
param => this.CanUnCheck
);
}
return _unCheckCommand;
}
}
My goal is to pass to the Command, as parameter, the element I select in my listview. How do I do that?
I did on my own:
<DataTemplate x:Key="CheckBoxDataTemplate">
<CheckBox IsChecked="{Binding
Path=IsSelected, Mode=TwoWay}"
HorizontalAlignment="Center"
VerticalAlignment="Center" Name="aDM_LEVEL_FIELDListView" Path="SelectedItem" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<WPFCtlr:EventToCommand Command="{Binding DataContext.UnCheckCommand, RelativeSource={RelativeSource FindAncestor,ListView,1}}" CommandParameter="{Binding ElementName=aDM_LEVEL_FIELDListView, Path=SelectedItem}" />
<!--<i:InvokeCommandAction Command="{Binding Path=SelectItemRelayCommand}" />-->
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
<!--Command="{Binding Path=DataContext.UnCheckCommand}"
CommandParameter="{Binding Path=IsChecked, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />-->
</DataTemplate>

Categories

Resources