Hiding wpf ContextMenu when the Data Grid is Empty? - c#

I am trying to make a simple TODO App with WPF using MVVM.
I have the tasks in Datagrid and a right click context menu with Delete option. I don't want the context menu to show when there are no elements in Data Grid. What can I do to solve it?
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DataGrid ItemsSource="{Binding Path=TaskList}" SelectedItem="{Binding SelectedTask}" AutoGenerateColumns="False">
<DataGrid.ContextMenu >
<ContextMenu>
<MenuItem Header="Delete" Command="{Binding OpenDialogCommand}" CommandParameter="{Binding PlacementTarget.SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"></MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.Columns>
<DataGridTextColumn Header="Priority" Width="auto" Binding="{Binding Path=Id}"/>
<DataGridTextColumn Header="Task" Width="auto" Binding="{Binding Path=TaskName}"/>
</DataGrid.Columns>
</DataGrid>

You could set the ContextMenu property conditionally using a Style with a Trigger:
<DataGrid ItemsSource="{Binding Path=TaskList}" SelectedItem="{Binding SelectedTask}" AutoGenerateColumns="False">
<DataGrid.Style>
<Style TargetType="DataGrid">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Delete" Command="{Binding OpenDialogCommand}"
CommandParameter="{Binding PlacementTarget.SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"></MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="HasItems" Value="False">
<Setter Property="ContextMenu" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Style>
<DataGrid.Columns>
<DataGridTextColumn Header="Priority" Width="auto" Binding="{Binding Path=Id}"/>
<DataGridTextColumn Header="Task" Width="auto" Binding="{Binding Path=TaskName}"/>
</DataGrid.Columns>
</DataGrid>

You could bind visibility and use the built in booleantovisibility converter
You need the converter. This could be in a resource dictionary you merge in app.xaml to use across the app.
<Window.Resources>
<BooleanToVisibilityConverter x:Key="booleanToVisibilityConverter"/>
</Window.Resources>
Then just bind visibility on the context menu
<DataGrid ...... >
<DataGrid.ContextMenu>
<ContextMenu Visibility="{Binding PlacementTarget.HasItems, RelativeSource={RelativeSource Self},
Converter={StaticResource booleanToVisibilityConverter}}">
<MenuItem Header="Delete"
Command="{Binding OpenDialogCommand}"
CommandParameter="{Binding PlacementTarget.SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"/>
</ContextMenu>
</DataGrid.ContextMenu>

As one of variations, you can use ContextMenuService.IsEnabled attached property and bind it with ItemsControl.HasItems.
<DataGrid ...
ContextMenuService.IsEnabled="{Binding RelativeSource={RelativeSource Self}, Path=HasItems}">

I got a simple hack to solve this. I changed the row definition from * to auto for row 2; This will stop context menu from showing when you click anywhere other than Datagrid Elements.
<RowDefinition Height="auto"/>
Also to remove one extra row which always shows(and display context menu when right clicked)
This worked.
<DataGrid Margin ="10" x:Name="dgTaks" Grid.Row="1" Grid.ColumnSpan="2" ItemsSource="{Binding Path=TaskList}" SelectedItem="{Binding SelectedTask}" AutoGenerateColumns="False" **CanUserAddRows="False"**>

Related

Bind Command To ContextMenu Item

I am getting this error/warning:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=DrivesListView'
When I press 'Refresh', the command does not fire. I am guessing since it is a ContextMenu, I need to somehow access the parent control in the binding path and then I can use MouseDownCommand.
MouseDownCommand is located in my tab viewmodel, TabItemViewModel. My MainWindowViewModel contains a list of TabItemViewModels, and that is the source of the TabControl's items.
What I've tried:
1)
I've tried setting the ContextMenu Opened event to set the DataContext manually like this to see if it would fix the DataContext somehow:
private void ContextMenu_Opened(object sender, RoutedEventArgs e)
{
ContextMenu menu = sender as ContextMenu;
ListView listView = menu.PlacementTarget as ListView;
Grid grid = listView.Parent as Grid;
TabControl tabControl = grid.Parent as TabControl;
menu.DataContext = (TabItemViewModel)tabControl.SelectedItem;
}
The problem with this is the fact that I cannot seem to get the tabControl from the grid. Doing .Parent just returns null for some unknown reason.
2)
I also tried setting the Tag of the control, which did not work either:
<ListView Grid.Row="1" Name="DrivesListView" ItemsSource="{Binding Drives}"
Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}">>
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Refresh">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction
Command="{Binding Path=PlacementTarget.Tag.MouseDownCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"
CommandParameter="{Binding ElementName=DrivesListView}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
</ContextMenu>
</ListView.ContextMenu>
<ListView.Style>
<Style TargetType="{x:Type ListView}" BasedOn="{StaticResource MahApps.Styles.ListView}">
<Style.Triggers>
<DataTrigger Binding="{Binding DrivesListViewEnabled}" Value="true">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding DrivesListViewEnabled}" Value="false">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Style>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding Path=MouseDoubleClickCommand}"
CommandParameter="{Binding ElementName=DrivesListView}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.View>
<GridView>
<GridViewColumn x:Name="NameHeader" Header="Name" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn x:Name="TypeHeader" Header="Type" DisplayMemberBinding="{Binding Type}"/>
<GridViewColumn x:Name="TotalSizeHeader" Header="Total Size" DisplayMemberBinding="{Binding TotalSize}"/>
<GridViewColumn x:Name="FreeSpaceHeader" Header="Free Space" DisplayMemberBinding="{Binding FreeSpace}"/>
</GridView>
</ListView.View>
</ListView>
Here is my XAML
<UserControl x:Class="FileExplorerModuleServer.Views.FileBrowserTabView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--ItemsSource is bound to the 'Tabs' property on the view-
model, while DisplayMemeberPath tells TabControl
which property on each tab has the tab's name -->
<TabControl Name="SubTabControl" Grid.Row="1"
ItemsSource="{Binding Tabs}"
DisplayMemberPath="Header" SelectedIndex="{Binding SelectedIndex}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding Path=TabChangedCommand}"
CommandParameter="{Binding ElementName=SubTabControl}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<TabControl.ContentTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" HorizontalAlignment="Left" Width="300" Text="{Binding Path}">
</TextBox>
<mah:ProgressRing Grid.Row="1" Height="1">
<mah:ProgressRing.Style>
<Style TargetType="{x:Type mah:ProgressRing}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsLoading}" Value="true">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding IsLoading}" Value="false">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</mah:ProgressRing.Style>
</mah:ProgressRing>
<ListView Grid.Row="1" Name="DrivesListView" ItemsSource="{Binding Drives}">
<ListView.ContextMenu>
<ContextMenu Opened="ContextMenu_Opened">
<MenuItem Header="Refresh">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction
Command="{Binding Path=MouseDownCommand}"
CommandParameter="{Binding ElementName=DrivesListView}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
</ContextMenu>
</ListView.ContextMenu>
<ListView.Style>
<Style TargetType="{x:Type ListView}" BasedOn="{StaticResource MahApps.Styles.ListView}">
<Style.Triggers>
<DataTrigger Binding="{Binding DrivesListViewEnabled}" Value="true">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding DrivesListViewEnabled}" Value="false">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Style>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding Path=MouseDoubleClickCommand}"
CommandParameter="{Binding ElementName=DrivesListView}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.View>
<GridView>
<GridViewColumn x:Name="NameHeader" Header="Name" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn x:Name="TypeHeader" Header="Type" DisplayMemberBinding="{Binding Type}"/>
<GridViewColumn x:Name="TotalSizeHeader" Header="Total Size" DisplayMemberBinding="{Binding TotalSize}"/>
<GridViewColumn x:Name="FreeSpaceHeader" Header="Free Space" DisplayMemberBinding="{Binding FreeSpace}"/>
</GridView>
</ListView.View>
</ListView>
Here is the ViewModel.cs
public ICommand MouseDownCommand
=> new RelayCommand<object>(e => MouseDown(e));
private void MouseDown(object commandParameter)
{
}
As stated in the documentation, [the] menu [...] is specific to the context of the control.
In other words, the ContextMenu has the same data context as it's parent control (here the ListView).
To follow the MVVM pattern, you then only need to add a ICommand in the data context of the ListView and bind it to the MenuItem.Command property.
The View:
<ListView ItemsSource="{Binding Drives}">
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Refresh" Command="{Binding RefreshCommand}" />
</ContextMenu>
</ListView.ContextMenu>
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Type" DisplayMemberBinding="{Binding Type}"/>
<GridViewColumn Header="Total Size" DisplayMemberBinding="{Binding TotalSize}"/>
<GridViewColumn Header="Free Space" DisplayMemberBinding="{Binding FreeSpace, StringFormat='{}{0:0.00}'}"/>
</GridView>
</ListView.View>
</ListView>
The ViewModel:
public class ViewModel
{
public ViewModel()
{
RefreshCommand = new ActionCommand(Refresh);
}
public IReadOnlyList<DriveViewModel> Drives { get; }
public ICommand RefreshCommand { get; }
private void Refresh()
{
// ...
}
}
Working demo available here.
First of all, MouseDown event doesn't seem to work well in the case of MenuItem. So, you need to use PreviewMouseDown or probaby Click event instread. Also, you cannot use ElementName for referring elements outside of ContextMenu.
Then, assuming DataContext of the ListView is implicitly bound to TabItemViewModel and you want to specify that ListView as CommandParameter, it could be modified as follows:
<MenuItem Header="Refresh">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction
Command="{Binding PlacementTarget.DataContext.MouseDownCommand, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"
CommandParameter="{Binding PlacementTarget, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>

Caliburn Micro Datagrid Context Menu

My items from context menu are not executing.
My xaml:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:arFirmaKomp.Views"
xmlns:arFirmaKomp="clr-namespace:arFirmaKomp" x:Class="arFirmaKomp.Views.ArKlienciView"
xmlns:helpers="clr-namespace:arFirmaKomp.ViewHelpers"
xmlns:cal="http://www.caliburnproject.org"
mc:Ignorable="d" Height="600" Width="1200" >
<Grid>
<ComboBox x:Name="ArKlienciList" SelectedItem="{Binding Path=WybranyArKlient, Mode=OneWayToSource}" DisplayMemberPath="PodmiotyOdbiorcaNazwaSkrocona" HorizontalAlignment="Left" Margin="128,49,0,0" VerticalAlignment="Top" Width="134" Height="22" />
<DataGrid x:Name="ArKlienciList2" ItemsSource="{Binding Path=ArKlienciICView}" SelectedItem="{Binding SelectedItem}"
cal:Message.Attach="[Event CellEditEnding]=[Action SaveChanges()];[Event MouseDoubleClick] = [Action RowSelect()]"
RowDetailsVisibilityMode="VisibleWhenSelected" Margin="17,80,10,20" EnableRowVirtualization="True" AutoGenerateColumns="False"
Tag="{Binding DataContext, RelativeSource={RelativeSource Self}}" >
<DataGrid.Resources>
<helpers:BindingProxy x:Key="proxy" Data="{Binding}" />
<ContextMenu x:Key="ContextMenu" cal:Action.TargetWithoutContext="{Binding}" IsOpen="{Binding Data.IsContextMenuOpen, Source={StaticResource proxy}}">
<MenuItem Header="Open"
cal:Message.Attach="Open($dataContext)">
</MenuItem>
</ContextMenu>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn x:Name="idColumn" Width="SizeToHeader" Header="Id" Binding="{Binding Id}"/>
<DataGridTextColumn x:Name="nexoKlientNabywcaColumn" Width="SizeToHeader" Header="Nexo Klient Nabywca" Binding="{Binding PodmiotyNabywcaNazwaSkrocona,Mode=OneWay}">
</DataGridTextColumn>
<DataGridTextColumn x:Name="nexoKlientOdbiorcaColumn" Width="SizeToHeader" Header="Nexo Klient Odbiorca" Binding="{Binding PodmiotyOdbiorcaNazwaSkrocona,Mode=OneWay}"/>
<DataGridTextColumn x:Name="nexoKlientOdbiorcaTelefonColumn" Width="SizeToHeader" Header="Nexo Odbiorca Telefon" Binding="{Binding OdbiorcaTelefon,Mode=OneWay}"/>
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="ContextMenu" Value="{StaticResource ContextMenu}" />
</Style>
</DataGrid.RowStyle>
</DataGrid>
<TextBox HorizontalAlignment="Left" x:Name="FilterString" Height="19" Margin="128,15,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="134"/>
<Label Content="filtr odbiorca" HorizontalAlignment="Left" Height="26" Margin="17,15,0,0" VerticalAlignment="Top" Width="92"/>
</Grid>
My viewmodel - contextmenu part:
public void Open(object source)
{
MessageBox.Show((string)source);
}
My bindingProxy is taken from Thomas Levesque Blog
I can see this context menu, and as I saw in other similar posts context menu is not connected with my ViewModel, and I don't know how to connect it. Contextmenu should make some action with the selected row as a parameter.

How to select listview item when clicking button

Inside my listview I´ve created a control template. Inside this template I made a button, so that every item inside mit listview has a button. This button represents an link which opens the directory that is shown. When I click the button, my program opens the explorer as I expect it. But when I click the button of an item that is not selected it opens the path of the selected item. So my question is, how can I change the selected item when I click the button inside my listview.
Here is how it looks like:
As you can see "R1" is selected, but I click on the link of "R3". What happens is, that C:\Temp\Folder1 gets opened, because "R1" is still the selecteditem. What I wish to is that C:\Temp\Folder3 gets opend. I think the trick should be that "R3" gets selected when clicking the button that represents the link. Does anyone know how to that?
This is my XAML-Code:
<ListView Grid.Row="1" ItemsSource="{Binding MyCollection}" FontSize="20" SelectedItem="{Binding SelectedMember, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="7,10,7,0" x:Name="ListView1" SelectionChanged="ListView1_SelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="Header 1" Width="150"/>
<GridViewColumn Header="Header 2" Width="120"/>
<GridViewColumn Header="Header 3" Width="120"/>
<GridViewColumn Header="Header 4" Width="560"/>
<GridViewColumn Header="Header 5" Width="100"/>
</GridView>
</ListView.View>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<EventSetter Event="MouseDoubleClick" Handler="ListViewItem_MouseDoubleClick"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="560"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0" Content="{Binding ID}" HorizontalAlignment="Center"/>
<ContentPresenter Grid.Column="1" Content="{Binding Name}" HorizontalAlignment="Center"/>
<ContentPresenter Grid.Column="2" Content="{Binding Description}" HorizontalAlignment="Center"/>
<Button Grid.Column="3" Content="{Binding Path}" Style="{StaticResource Link}" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.GoToPathCommand }" HorizontalAlignment="Left" Margin="5,0,0,0" IsEnabled="{Binding ButtonEnabled}"/>
<ContentPresenter Grid.Column="4" Content="{Binding Owner}" HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="DarkBlue"/>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.GoToPathCommand }"
This Command will jump to the Cmd of the ViewModel. I assume that the Command will check which item is selected and it will access it's property Path.
Avoiding this behavior, You can create a Command that will take a parameter and set it from Binding:
<Button Content="{Binding Path}"
Command="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}, Path=DataContext.GoToPathCommand }"
CommandParameter="{Binding Path}"/>
Now the command itself must be adjusted:
public MyCmd : ICommand
{
public void Execute(object parameter)
{
string path = (string) parameter;
//Open the path via explorer
}
}
Try adding below trigger too in the ListViewItem Style
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True"/>
</Trigger>
</Style.Triggers>

Unable to use MahApps style DataGrid within a UserControl

I'm pretty new to WPF, so I apologise in advance if the answer to this question is verysimple. I have looked around everywhere, but can't find an appropriate solution.
The low-down:
I have an application that is using MahApps. The Windows within my app work fine. I can set style and change themes, and it applies across all the windows.
The issue is that within my MainWindow I have a couple of UserControls. One of these UserControls has a DataGrid, and for some reason, the DataGrid will not take the default MahApps DataGrid style.
One other thing: My DataGrid uses DataTriggers to display different observable lists depending on a RadioButton that has been pressed. It therefore doesn't let me set the style of the DataGrid (as per the MahApps guide here: http://mahapps.com/controls/datagrid.html).
MahApps suggestion:
<DataGrid ItemsSource="{Binding People}" Margin="10,20,10,0"
AutoGenerateColumns="True"
Style="{StaticResource AzureDataGrid}">
Another suggestion I found was to add the MahApps resources to the Resource dictionary of my UserControl. That didn't work, so I removed that code.
My current UserControl xaml:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TrayportLibrary.Home"
xmlns:helpers="clr-namespace:TrayportLibrary.Helpers"
xmlns:controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
x:Class="TrayportLibrary.Search.SearchView"
mc:Ignorable="d" >
<UserControl.Resources>
<helpers:StringToVisibilityConverter x:Key="StringToVisibilityConverter"/>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</UserControl.Resources>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<ei:CallMethodAction TargetObject="{Binding}" MethodName="LoadCollections"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<StackPanel FocusManager.FocusedElement="{Binding ElementName=SearchBox}">
<Grid Name="MainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox x:Name="SearchBox"
Focusable="True"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Text="{Binding SearchInput, UpdateSourceTrigger=PropertyChanged}"
Width="200"
Height="25"
BorderBrush="Black"
BorderThickness="2"
Grid.Column="0"
Grid.Row="0"
Margin="0,0,5,0"/>
<StackPanel Grid.Column="1"
Grid.Row="0"
Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Left">
<RadioButton GroupName="SearchSelection"
Name="BookRadio"
Content="Books"
Margin="0,0,5,0"
IsChecked="{Binding SearchBook}"
Command="{Binding SetSearchCommand}"
CommandParameter="book"
Click="RadioButton_OnClick"/>
<RadioButton GroupName="SearchSelection"
Name="MemberRadio"
Content="Members"
IsChecked="{Binding SearchMember}"
Command="{Binding SetSearchCommand}"
CommandParameter="member"
Click="RadioButton_OnClick"/>
</StackPanel>
<FrameworkElement Grid.Row="1" Grid.Column="0" x:Name="Proxy"/>
<DataGrid Name="DataGrid"
Grid.Row="1"
Grid.ColumnSpan="2"
Grid.Column="0"
IsReadOnly="True"
AutoGenerateColumns="False"
Height="200"
VerticalScrollBarVisibility="Auto"
Visibility="{Binding Path=Text,
ElementName=SearchBox,
Converter={StaticResource
StringToVisibilityConverter}}">
<DataGrid.Columns>
<DataGridTextColumn Header="Book ID" Binding="{Binding BookID}" Visibility="{Binding DataContext.BookVisibility, Converter={StaticResource BooleanToVisibilityConverter}, Source={x:Reference Proxy}, Mode=TwoWay, NotifyOnSourceUpdated=True}"/>
<DataGridTextColumn Header="Title" Binding="{Binding Title}" Visibility="{Binding DataContext.BookVisibility, Converter={StaticResource BooleanToVisibilityConverter}, Source={x:Reference Proxy}, Mode=TwoWay, NotifyOnSourceUpdated=True}"/>
<DataGridTextColumn Header="Author(s)" Binding="{Binding AuthorData}" Visibility="{Binding DataContext.BookVisibility, Converter={StaticResource BooleanToVisibilityConverter}, Source={x:Reference Proxy}, Mode=TwoWay, NotifyOnSourceUpdated=True}"/>
<DataGridTextColumn Header="Date Due" Binding="{Binding DateDue, StringFormat=dd/MM/yyyy}" Visibility="{Binding DataContext.BookVisibility, Converter={StaticResource BooleanToVisibilityConverter}, Source={x:Reference Proxy}, Mode=TwoWay, NotifyOnSourceUpdated=True}"/>
<DataGridCheckBoxColumn Header="Out" Binding="{Binding IsOut}" Visibility="{Binding DataContext.BookVisibility, Converter={StaticResource BooleanToVisibilityConverter}, Source={x:Reference Proxy}, Mode=TwoWay, NotifyOnSourceUpdated=True}"/>
<DataGridTextColumn Header="On Loan to" Binding="{Binding OnLoanToUserName}" Visibility="{Binding DataContext.BookVisibility, Converter={StaticResource BooleanToVisibilityConverter}, Source={x:Reference Proxy}, Mode=TwoWay, NotifyOnSourceUpdated=True}"/>
<DataGridCheckBoxColumn Header="Lost" Binding="{Binding IsLost}" Visibility="{Binding DataContext.BookVisibility, Converter={StaticResource BooleanToVisibilityConverter}, Source={x:Reference Proxy}, Mode=TwoWay, NotifyOnSourceUpdated=True}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Visibility="{Binding DataContext.MemberVisibility, Converter={StaticResource BooleanToVisibilityConverter}, Source={x:Reference Proxy}, Mode=TwoWay, NotifyOnSourceUpdated=True}"/>
<DataGridTextColumn Header="Username" Binding="{Binding UserName}" Visibility="{Binding DataContext.MemberVisibility, Converter={StaticResource BooleanToVisibilityConverter}, Source={x:Reference Proxy}, Mode=TwoWay, NotifyOnSourceUpdated=True}"/>
<DataGridTextColumn Header="Books on Loan" Binding="{Binding BooksOnLoan}" Visibility="{Binding DataContext.MemberVisibility, Converter={StaticResource BooleanToVisibilityConverter}, Source={x:Reference Proxy}, Mode=TwoWay, NotifyOnSourceUpdated=True}"/>
<DataGridTextColumn Header="Books Overdue" Binding="{Binding BooksOverdue}" Visibility="{Binding DataContext.MemberVisibility, Converter={StaticResource BooleanToVisibilityConverter}, Source={x:Reference Proxy}, Mode=TwoWay, NotifyOnSourceUpdated=True}"/>
</DataGrid.Columns>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<ei:CallMethodAction MethodName="OnSelectedItem" TargetObject="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<DataGrid.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MemberRadio, Path=IsChecked}" Value="true">
<Setter Property="DataGrid.ItemsSource" Value="{Binding Members}"/>
<Setter Property="DataGrid.SelectedItem" Value="{Binding SelectedMember}"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=BookRadio, Path=IsChecked}" Value="true">
<Setter Property="DataGrid.ItemsSource" Value="{Binding Books}"/>
<Setter Property="DataGrid.SelectedItem" Value="{Binding SelectedBook}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Style>
</DataGrid>
</Grid>
</StackPanel>
Any advice/code/best practise would be greatly appreciated.
I'm also aware that my current xaml could probably be made simpler, but I just want to sort this issue first before I start refactoring.
Thanks in advance.
The problem is that you are overriding the style that would normally be applied to the DataGrid with your own custom style.
Your custom style can inherit setters from other styles by using the BasedOn attribute.
For example:
<Style BasedOn="{StaticResource AzureDataGrid}">
Or to inherit from the default style for the control type:
<Style BasedOn="{StaticResource {x:Type DataGrid}}">

WPF Gridview ContextMenu

Does anybody know how to add a ContextMenu to each row in a GridView? The following example works but adds the contextmenu to the whole control, also on the empty space, scrollbar, header, etc.. Thanks for any help.
<GridView ContextMenu="{StaticResource DisplayedContextMenu}" ItemsSource="{Binding Data}" >
<GridView.View>
<GridView>
<GridViewColumn Header="Position" Width="0" DisplayMemberBinding="{Binding Position}" />
...
<DataGrid Name="grid">
<DataGrid.Resources>
<Style TargetType="DataGridRow">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Copy Row" />
<MenuItem Header="Paste Row" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Copy Grid" />
<MenuItem Header="Paste Grid" />
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
In case of ListView you should override style for ListViewItem and etc.

Categories

Resources