I have a DevExpress grid control and I want to disable the default context menu that appears when I right click the Grid column headers. To disable this functionality I handled the PreviewMouseRightButtonDown and PreviewMouseRightButtonUp
private void UserControl_PreviewMouseRightButtonDown_Up(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
e.Handled = true;
}
This is not an acceptable solution. There should be should be something on grid control.
Please set the TableView.IsColumnMenuEnabled property to control whether the column context menu is shown when an end-user right-clicks a column's header.
You can read more about all avilable DXGrid's context menus and its customization here: Context Menus
Set IsColumnMenuEnabled="False" on your TableView.
If you want disable specific context menu item you can manage it by binding
<dxb:BarButtonItem Name="contexMenuTransmitPendingClaim"
Command="{Binding Path=(dxb:GridPopupMenuBase.GridMenuInfo).View.DataContext.TransmitPendingClaimCommand,
RelativeSource={RelativeSource Self}}"
Content="Transmit Pending Claim"
IsEnabled="{Binding Path=(dxb:GridPopupMenuBase.GridMenuInfo).View.DataContext.SelectedCusHisViewRefillHistory.IsPendingClaimsActive,
RelativeSource={RelativeSource Self},
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"/>
Related
There are basically two things I am trying to activate or implement:
1. Clearing selection when background is clicked:
Typically, when one clicks in a blank area of a list view type control, such as windows explorer, any selected items become unselected. This is not happening for me in either multiple or extended selection mode. Do I have to manually handle the mouse click event to clear the selection, or is it perhaps not behaving as expected because I've applied a background to the control?
2. Selection rectangle with automatic scrolling:
Before porting my application to WPF, the standard WinForms listview allowed me to drag a selection rectangle and it would select any items it intersected. If there were items scrolled out of view in any direction, dragging in that direction would result in the control automatically scrolling into that area as I dragged the mouse, so I could selected items that are out of view. Does the WPF ListView implement this feature, or am I going to have to implement it myself? Someone posted a non-trivial implementation involving hittests in the comments on this page (http://social.msdn.microsoft.com/Forums/vstudio/en-US/191af722-e32b-4e6d-a00b-9ad2b53ea3b9/listview-dragging-a-selection-box-around-items?forum=wpf), but it doesn't even support the autoscrolling and I'm having a hard time believing Microsoft just left this feature out.
Really ListView has no default appearance and you had to do set even basic selection with trigger.
Wow, this colors and displays the SelectedIndex without a single style or trigger.
All in XAML
<Window.Resources>
<sys:String x:Key="MyString">Hello</sys:String>
<x:Array x:Key="MyStringArray" Type="sys:String">
<sys:String>Hello</sys:String>
<sys:String>World</sys:String>
<sys:String>Continent</sys:String>
<sys:String>Universe</sys:String>
</x:Array>
</Window.Resources>
<Grid>
<StackPanel Orientation="Vertical">
<ListView ItemsSource="{StaticResource MyStringArray}" x:Name="lv" SelectionMode="Single" LostFocus="lv_LostFocus">
</ListView>
<TextBlock Text="{Binding ElementName=lv, Path=SelectedIndex}" />
<Button Content="Take Focus"/>
</StackPanel>
</Grid>
private void lv_LostFocus(object sender, RoutedEventArgs e)
{
lv.SelectedIndex = -1;
}
I need a button-style menu, i.e. horizontally arranged group of always visible buttons.
Like radiobuttons they should have a selected property, i.e. the click-command should fire only when the selected status changes to true, not on every click as with a normal button.
Dude, this is WPF, you can use any control that fits some or any of your requirements and then simply provide a new ControlTemplate for it. Incidentally, there is no Selected or IsSelected property on a RadioButton... perhaps you were referring to the IsChecked property? This property is inherited from the ToggleButton, so that may be more appropriate.
As the ToggleButton is already a Button, you could even get away without providing a new ControlTemplate for it.
As for your requirement regarding the Click event, I don't think that you will find that functionality on any of the WPF controls, but it could be manually implemented:
private void Button_Click(object sender, RoutedEventArgs e)
{
if (ToggleButton.IsChecked == true)
{
// Do something here when the `Button.IsChecked` == true
}
}
RadioButton also like other Buttons fire Click event on every click. Also there is no Selected property on the RadioButton.
But if you want your MenuItems to be like Button, then you can use ToggleButton here.
ToggleButton has IsChecked Property which tracks the checked state of button and Checked event which is fired when ToggleButton is Checked.
Also, if you want to automatically check/uncheck your ToggleButtons on click of other ToggleButton then you can use RadioButton as DataTemplate of your MenuItem and override its Template like below:
<RadioButton Content="MyRadio" Click="RadioButton_Click">
<RadioButton.Template>
<ControlTemplate TargetType="RadioButton">
<ToggleButton Checked="ToggleButton_Checked" IsChecked="{Binding IsChecked, RelativeSource={RelativeSource TemplatedParent}}" Content="{TemplateBinding Content}"/>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
It turned out that a ListBox with a horizontal layout in a WrapPanel suits my scenario perfectly.
I posted the solution in another question.
Within a Listbox control I have a Data Template which consists of text and a button. Given the nature of Silverlight/WPF when I click on the button within the listbox item the button event is trapped before the listbox item is selected. Therefore if I am trying to pass the record ID of the selected listbox item I am currently only able to do so by first clicking and selecting the listbox item and then clicking on the button.
Is there a way to promote the selection of the listbox item so that when the listbox items are created I have the ability to click on the button within the listbox item and some event (selectionChanged ?) is invoked which would allow me to capture the selected record id and use it for some other action ( pass as a parameter in a method etc). I'm using Simple MVVM toolkit for this implementation so I was wondering if this could be handled in the viewModel or if I would need to handle this in the controls code behind and then push the selection to the viewModel.
The listbox control is presented as:
<ListBox x:Name="ResultListBox"
HorizontalAlignment="Stretch"
Background="{x:Null}"
Grid.Row="1"
BorderThickness="0" HorizontalContentAlignment="Stretch"
ItemContainerStyle="{StaticResource ListBoxItemStyle1}"
ItemsSource="{Binding SearchResults[0].Results}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Style="{StaticResource ListBoxStyle1}">
<ListBox.ItemTemplate>
<DataTemplate>
<dts:TypeTemplateSelector Content="{Binding}" HorizontalContentAlignment="Stretch">
<!-- Template 1 -->
<formatter:TypeTemplateSelector.CFSTemplate>
<DataTemplate>
<qr:ucIndex_Product />
</DataTemplate>
</formatter:TypeTemplateSelector.CFSTemplate>
<!-- Template 2 -->
<formatter:TypeTemplateSelector.PersonTemplate>
<DataTemplate>
<qr:ucIndex_Person />
</DataTemplate>
</formatter:TypeTemplateSelector.PersonTemplate>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Within the datatemplate (user control) resides the button along with a number of other fields. I'll omit that code for the time being unless requested.
Thanks in advance!
Put this in your ListBox.Resources
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter Event="PreviewGotKeyboardFocus" Handler="SelectCurrentItem"/>
</Style>
And this in the Code Behind
protected void SelectCurrentItem(object sender, KeyboardFocusChangedEventArgs e)
{
ListBoxItem item = (ListBoxItem)sender;
item.IsSelected = true;
}
You could use the following code as well which doesn't use code-behind, however it only keeps the ListBoxItem selected for as long as it has KeyBoard focus. Once focus leaves, the item becomes unselected
<Style TargetType="ListBoxItem">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
EDIT
Since Silverlight doesn't have EventSetters, you can use the ListBox's Loaded event and add the following to your code behind:
private void ResultListBox_Loaded(object sender, RoutedEventArgs e)
{
ListBox list = (ListBox)sender;
list.GotFocus += ResultListBox_GotFocus;
}
void ResultListBox_GotFocus(object sender, RoutedEventArgs e)
{
var item = FindAncester<ListBoxItem>((DependencyObject)e.OriginalSource);
if (item != null) item.IsSelected = true;
}
T FindAncester<T>(DependencyObject current)
where T : DependencyObject
{
current = VisualTreeHelper.GetParent(current);
while (current != null)
{
if (current is T)
{
return (T)current;
}
current = VisualTreeHelper.GetParent(current);
};
return null;
}
This captures the Focus event for the ListBox, takes the control that triggered the focus event and traverses up the visual tree to find the ListBoxItem objects, and sets it's Selected value to true.
Rachel's solution works great. The one issue I did find in this approach was that it does place total focus on the selected item. As a result the user would be required to double click within the control to place focus on other items such as selectable text or other button. After working with this a bit more I discovered you can also resolve this by setting the listbox selected items to the data context of the object you are clicking on etc. This works well as allows you to set this to any UI object within the control.
ListBox.SelectedItem = ((HyperlinkButton)sender).DataContext;
In this example I had Hyperlink buttons within the data template. Clicking on them would then set the focus to the selected listbox item.
rlcrews got it right! Use DataContext:
ObservableCollection<Employee> employees1;
...
listBox1.ItemsSource = employees1;
...
//DataTemplate in ListBox has a button with following event
private void bnPromoteEmployee_Click(object sender, RoutedEventArgs e)
{
Employee emp1 = (Employee)((Button)sender).DataContext;
emp1.Promote();
}
I have developed a WPF UserControl that is intended to be used as a pick list as follows:
A DataGrid bound to a CollectionView of entities (e.g. of Employees)
A TextBox above the DataGrid that can be used to filter items displayed in the DataGrid.
I want to expose a Command that will be executed when the user double-clicks on a row in the DataGrid. The container can then react to this by doing something with the SelectedItem in the DataGrid.
So far I've tried to handle the double-click as follows:
<DataGrid IsReadOnly="True">
<DataGrid.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="... />
</DataGrid.InputBindings>
...
However the double-click event still fires when the user clicks in the DataGrid header. I'd like to be able to limit it so that the Command is only executed when the double click is in the body of the DataGrid. Is there a declarative way to do this?
UPDATE
I'm just getting to grips with WPF and MVVM, and am really looking for guidance on how to implement low-level reusable components like this. Any general advice will also be gratefully received and upvoted. As it stands, I'm assuming I will want this UserControl to:
Expose a dependency property "SelectedItem" that is bound to the DataGrid's SelectedItem
Expose a RoutedEvent "ItemDoubleClick" or similar that is fired when the user double-clicks on a row.
Implement ICommandSource and call CommandHelpers.ExecuteCommandSource(this) from the row double-click event handler.
If code behind is not a problem:
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<EventSetter Event="Loaded" Handler="Row_Loaded"/>
</Style>
</DataGrid.RowStyle>
private void Row_Loaded(object sender, RoutedEventArgs e)
{
var row = sender as DataGridRow;
row.InputBindings.Add(new MouseBinding(MyCommands.MyCommand,
new MouseGesture() { MouseAction = MouseAction.LeftDoubleClick }));
}
You can simply put the DataGrid into a Grid and define your InputBindings in the Grid. In the canExecute-definition, you should check, if a row is selected. That works for the KeyBinding as well, for example a custom Delete-Command.
<Grid>
<Grid.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="... />
</Grid.InputBindings>
<DataGrid IsReadOnly="True">
...
</Grid>
I created programatically a class (I called it ViewGrid) so that I use an instance of it as ItemTemplate for my ListBox control; of course, it's my data template for the listboxitem....
Also, in my ViewGrid class, I got a dependency property called IsChecked and I want to keep it in sync with the ListBoxItem's IsSelected property. I noticed that in SL there no relativesource-findancestor-ancestortype support for binding as in WPF, still, I need to find a way to keep my IsChecked property synchronized with the IsSelected property of the internally generated ListBoxItem for my ListBox control. Can you help?
Here is a ListBox defined in XAML that uses the IsSelected property of each LitBoxItem to show or hide a button when selected. You just need to duplicate that Binding approach for the ListBoxItems you create in code. Either that, or create a UserControl with the appropriate ListBoxItem XAML, and insert instances of those UserControls into your ListBox.
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="200" Height="120">
<StackPanel Margin="5">
<TextBlock Text="{Binding Name, Mode=OneWay}" />
<StackPanel Visibility="{Binding IsSelected, Mode=OneWay, Converter={StaticResource BoolToVisible}}">
<Button Content="Show Details" Click="OnDetailsClick" Tag="{Binding}" />
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Good luck,
Jim McCurdy
Face To Face Software and YinYangMoney
UPDATE: I revisited this and found a much better solution. My original one remains below, but the way I actually ended up solving this problem is via using the ViewGrid in a ControlTemplate instead of a DataTemplate. Then you can use the RelativeSource TemplatedParent binding to bind to the IsSelected property of the ListBox. So, add the following to the Resources of the listbox or your page or user control:
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<StackPanel>
<ViewGrid IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"/>
<!-- other controls may go here -->
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
ORIGINAL:
So after seven years, you almost certainly don't need an answer to this anymore... however, I recently spent a morning wrestling with this issue and thought I'd give my solution in case any similar unfortunate ends up here.
First off, anyone who's using Silverlight 5 is in luck as AncestorType is apparently now available for RelativeSource, letting you bind directly to the IsSelected property of the ListBoxItem. For those of us stuck with 4 or below, the only real workaround I came up with was "faking" the binding via use of events in the code behind.
To do this, assume you have your YourView XAML with a ListBox named "lbYourListBox" which has its ItemsSource and SelectedItem properties bound to appropriate properties on a YourViewModel class, along with a ViewGrid in its ItemTemplate whose IsChecked property is not bound to anything. Then, in your code behind file, you wire up events as follows:
public YourView()
{
InitializeComponent();
this.Loaded += (sender, e) =>
{
((YourViewModel)this.DataContext).PropertyChanged += vm_PropertyChanged;
UpdateViewGrids();
};
}
// this part propagates changes from the view to the view model
private void viewGrid_Checked(object sender, RoutedEventArgs e)
{
var selectedVM = ((ViewGrid)sender).DataContext as SourceItemType;
((YourViewModel)this.DataContext).SelectedViewGridItem = selectedVM;
}
private void vm_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (string.Equals(e.PropertyName, "SelectedViewGridItem"))
{
UpdateViewGrids();
}
}
// this part propagates changes from the view model to the view
private void UpdateViewGrids()
{
var viewGrids = this.lbYourListBox.GetVisualDescendants().OfType<ViewGrid>();
var selectedVM = ((YourViewModel)this.DataContext).SelectedViewGridItem;
foreach (var grid in viewGrids)
{
grid.IsChecked = selectedVM == grid.DataContext;
}
}
The viewGrid_Checked event handler should be wired up to the Checked event of the view grid in the ItemTemplate. The GetVisualDescendants() method comes from the Silverlight Toolkit.
Important caveats:
The ViewGrid.Checked event should not fire except for the unchecked->checked transition, and no more than one view grid should be able to be selected at once. If those two things aren't true, you'll have to make appropriate edits to ensure this code can't cause an infinite event-driven loop. (Of course, if you don't need two-way binding, you only need one of these event handlers and event ping-pong isn't a concern.)
I wrote this for a user control which had its data context set in XAML, which is why the event handler for the view model's PropertyChanged event is only assigned after the view is loaded. Depending on how and when your view and view model are bound to each other, you may have to assign that earlier/later/differently.
This won't work if the view grids aren't visible, GetVisualDescendants seems to ignore hidden/collapsed controls.