Telerik RadTreeListView : Attaching event in rows - wpf

I'm using telerik radgridview in my WPF app
<telerik:RadTreeListView Grid.Row="1" Grid.ColumnSpan="2"
Name="WorkPreferenceTreeView"
AutoGenerateColumns="false"
IsReadOnly="True"
ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Views:WorkPreferenceSelectorView}}}"
RowIndicatorVisibility="Collapsed"
SelectedItem="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Views:WorkPreferenceSelectorView}}}"
ScrollViewer.HorizontalScrollBarVisibility="Hidden">
<TelerikNavigation:RadContextMenu.ContextMenu>
<TelerikNavigation:RadContextMenu x:Name="RadContextMenu" />
</TelerikNavigation:RadContextMenu.ContextMenu>
<telerik:RadTreeListView.ChildTableDefinitions>
<telerik:TreeListViewTableDefinition ItemsSource="{Binding ItemPreferences}" />
</telerik:RadTreeListView.ChildTableDefinitions>
<telerik:RadTreeListView.Columns>
<telerik:GridViewDataColumn MinWidth="200" Width="*" CellTemplate="
{StaticResource ItemPreferenceskPreferenceCellTemplate}" Header="Preference" IsFilterable="false"
ShowFieldFilters="false" Name="A" />
And Im attaching an event on the control
private void InitializeControl()
{
WorkPreferenceTreeView.MouseDoubleClick += (WorkPreferenceTreeView_MouseDoubleClick);
}
Now my problem is the MouseDoubleClick event fires whenever I double click ANYWHERE in the radtreelistview (even in the Scroll Bar) where I just want it to fire when a selected item or row is double clicked. I'm wondering if I can just attach the MouseDoubleClick even in the selected item or each of the rows but I have no luck of finding way to do that. Any suggestion?

in your example, you did attached the event on the grid itself.
in fact you need to attach the event on the Row !
you can do it with RowStyle
(in this example, double click will toggle the IsExpanded row property)
<telerik:RadTreeListView ... >
<telerik:RadTreeListView.RowStyle>
<Style TargetType="telerik:TreeListViewRow">
<EventSetter
Event="MouseDoubleClick"
Handler="HandleRowDoubleClick" />
</Style>
</telerik:RadTreeListView.RowStyle>
</telerik:RadTreeListView>
and the code behind
public void HandleRowDoubleClick(object sender, RoutedEventArgs e)
{
var row = sender as Telerik.Windows.Controls.GridView.GridViewRow;
row.IsExpanded = !row.IsExpanded;
}
enjoy :)

Related

Binding command parameter of data grid context menu to selected row's column value

I have a datagrid being binded to an ObservableCollection. The data grid has a context menu. When context menu item is clicked, the binded command gets triggered, but I would like to pass command parameter that is binded to the Id of the data grid row that is selected. The command gets triggered but the parameter is null.
Below is the code that I have tried.
<DataGrid Name="users" ItemsSource="{Binding UsersModel}" CanUserAddRows="False" IsReadOnly="True" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Id}" Header="User Id" Width="auto"/>
<DataGridTextColumn Binding="{Binding Name}" Width="*" Header="User Name"/>
<DataGridTextColumn Binding="{Binding IsRegistered, Converter={StaticResource BoolToYesNoConverter}}" Width="auto" Header="Registered" />
<DataGridTextColumn Binding="{Binding RegisteredOn}" Width="*" Header="Registration Date"/>
</DataGrid.Columns>
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Modify" Command="{Binding Modify}" CommandParameter="{Binding Id}"/>
<MenuItem Header="Delete" Command="{Binding Delete}" CommandParameter="{Binding Id}" />
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
I am expecting the Id of the selected row be passed as the command parameter.
I would create a SelectedRow property on your viewmodel to store the selected row in the grid, then bind the context menu item command to a command on the viewmodel that references the SelectedRow property.
I had to use the PlacementTarget on the context menu relative source.
// in viewmodel
public DelegateCommand ModifyCommand { get; }
ModifyCommand = new DelegateCommand(() => { var Id = SelectedRow.Id; //... });
private UsersModel _selectedRow;
public UsersModel SelectedRow
{
get => _selectedRow;
set
{
_selectedRow = value;
OnPropertyChanged(nameof(SelectedRow));
}
}
// in view
DataGrid Name="users" ItemsSource="{Binding Items}" CanUserAddRows="False" IsReadOnly="True" AutoGenerateColumns="False"
SelectedItem="{Binding SelectedRow, Mode=TwoWay}" >
// and on context menu
<MenuItem Header="Modify" Command="{Binding PlacementTarget.DataContext.ModifyCommand,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}" />
Add a SelectedId property to your view model (where the UsersModel and the command properties are defined) and bind the DataGrid's SelectedValue property to that property.
Then use SelectedId for the CommandParameter Binding. Of course make sure that SelectedId fires the PropertyChanged event.
<DataGrid ... SelectedValuePath="Id" SelectedValue="{Binding SelectedId}">
...
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Modify"
Command="{Binding Modify}"
CommandParameter="{Binding SelectedId}"/>
<MenuItem Header="Delete"
Command="{Binding Delete}"
CommandParameter="{Binding SelectedId}" />
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
I asuume that your ViewModel class implemented INotifyPropertyChanged interface and I assume that you implement a method for trigger property changes, here I called this method RaisePropertyChanged. After all of that,
define a private field selectedUsers and a property with name of SelectedUsers in your viewModel Class:
private UsersModel selectedUsers;
public UsersModel SelectedUsers
{
get => _selectedFields;
set
{
_selectedFields = value;
Modify.RaiseCanExecuteChanged();
Delete.RaiseCanExecuteChanged();
}
}
After that you add it, you must add SelectionChanged event to your Grid, and then in code-behind set-up value for your seletedUser as below:
private void usersGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
usersViewModel.SelectedUsers = usersGrid.SelectedItem as UsersModel;
}
And bind selectedItem of DataGrid to selectedUser:
<DataGrid Name="users" ItemsSource="{Binding Items}" CanUserAddRows="False"
IsReadOnly="True" AutoGenerateColumns="False"
SelectedItem="{Binding SelectedUser}" >
When you do these work, selectedUser is accessable in your viewModel.

How to get the checkbox column sender's datagrid parent

Hi I have a datagrid (xaml code below):
<DataGrid.Columns>
<DataGridTextColumn Header="FLEET" IsReadOnly="True" Width="1*" Binding="{Binding FLEET, UpdateSourceTrigger=PropertyChanged}" />
<DataGridTemplateColumn Header="SELECTED?" Width="1*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Viewbox Margin="-0.2" Height="18.5">
<CheckBox IsThreeState="True" IsChecked="{Binding Path=isSelected, UpdateSourceTrigger=PropertyChanged}" Click="FSC_CheckBox_Click"/>
</Viewbox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
The click events:
private void FSC_CheckBox_Click(object sender, RoutedEventArgs e)
{
......
}
Is there a way I can get the the parent datagrid object from the click sender? I've tried this link
Get containing row from a CheckBox inside of a DataGrid, but it didn't work because of the viewbox and datatemplate(I guess).
Any suggestions is appreciated. Thank you.
The click event handler will get the sender, which you can cast to checkbox.
I reckon the simplest approach is to abuse the Tag property on your checkbox.
That can be any old object you fancy.
You can use a relativesource binding for that.
Something like:
<CheckBox Tag="{Binding RelativeSource={Relativesource AncestorType=DataGrid}}"
Grab it off there, roughly:
private void FSC_CheckBox_Click(object sender, RoutedEventArgs e)
{
var cb=(CheckBox)sender;
var parentDataGrid = (DataGrid)cb.Tag;
}
This is air code, I don't have a datagrid with a checkbox and a click handler to try it out with easily so there may be some typo lurking.

How to unsubscribe from Check/Uncheck event of datagridcheckbox column in WPF?

I subscribed to the Check/Uncheck event via cell style, like below.
<DataGridCheckBoxColumn x:Name="colAccept" Binding="{Binding Accepted}" Header="Accepted">
<DataGridCheckBoxColumn.CellStyle>
<Style>
<EventSetter Event="CheckBox.Checked" Handler="OnChecked_Accepted"/>
<EventSetter Event="CheckBox.Unchecked" Handler="OnUnchecked_Accepted"/>
</Style>
</DataGridCheckBoxColumn.CellStyle>
</DataGridCheckBoxColumn>
I am updating the property that is bound to this column from the code behind but would not like the event to fire that one time. In winforms, I would unsubscribe from the event, then uncheck the checkbox, and then resubscribe, but how could I do this in WPF xaml?
Its easier to use a DataGridTemplateColumn instead.
<DataGridTemplateColumn Header="Accepted">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Mode=OneWay}" Checked="OnChecked_Accepted" Unchecked="OnUnchecked_Accepted" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
in the handler
private void OnUnchecked_Accepted(object sender, RoutedEventArgs e)
{
var cb = sender as CheckBox;
cb.Unchecked -= OnUnchecked_Accepted; //this line unsubscribes the event
}

ListBox with hyperlink -> selection changed

I want to do with xaml bindings such feature:
Listbox contains hyperlinks.
When hyperlink clicked - we go to another frame
But also SelectedItem must changed, and on another frame we show info about selected item.
I want it without subscribing click/selected events. Only declarative
Example of my listbox
<ListBox Grid.Row="1"
x:Name="OrderTypesListBox"
ItemsSource="{Binding OrderTypes, Mode=OneWay}"
SelectedItem="{Binding SelectedCall.OrderType, Mode=TwoWay}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}" />
<HyperlinkButton Style="{StaticResource LinkStyle}" NavigateUri="/WindowPage" TargetName="ContentFrame" Content="WindowPage"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now solve like that
<ListBox Grid.Row="1"
x:Name="OrderTypesListBox"
ItemsSource="{Binding OrderTypes, Mode=OneWay}"
SelectedItem="{Binding SelectedCall.OrderType, Mode=TwoWay}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<HyperlinkButton
TargetName="ContentFrame"
NavigateUri="{Binding OrderTypeNextPage}"
Content="{Binding Name}"
Click="HyperlinkButton_Click"
Tag="{Binding}"
/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
OrderTypesListBox.SelectedItem = (sender as HyperlinkButton).Tag;
}
Don't use a HyperlinkButton. Perform the needed actions when the SelectedItem changes in your ViewModel.
Edit: If you need to respond to all click events even if the item is already selected then you can use a Behavior to do this. Just create a behavior for the TextBlock that navigates on the TextBlock click event.
Edit2: Behaviors are pretty simple to code up and easy to use (and don't break the MVVM paradigm).
public class NavigatingTextBlockBehavior : Behavior<TextBlock>
{
protected override void OnAttached()
{
AssociatedObject.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseDown);
}
private void OnMouseDown(object sender, MouseButtonEventArgs e)
{
NavigationService.Navigate(new Uri("/WindowPage"));
}
}

How to find sibling of a control that raised an event in DataGrid WPF

I have a DataGrid whole columns are given below.
<my:DataGrid.Columns>
<my:DataGridTemplateColumn Header="Last Name" MinWidth="160" SortMemberPath="[LAST_NAME]">
<my:DataGridTemplateColumn.CellTemplate >
<DataTemplate>
<TextBlock Name="lblLastName" Padding="5"
Text="{Binding [LAST_NAME]}" />
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
</my:DataGridTemplateColumn>
<my:DataGridTemplateColumn Header="New Age Group" IsReadOnly="True"
MinWidth="130">
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox SelectedValue="{Binding AgeGroupId}"
DisplayMemberPath="AgeGroupName" ItemsSource="{Binding}"
Name="ddlNewAgeGroup" Loaded="ddlNewAgeGroup_Loaded"/>
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
</my:DataGridTemplateColumn>
<my:DataGridTemplateColumn Header="Update" MinWidth="75" Width="100">
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Update" Name="btnUpdate" Click="btnUpdate_Click"/>
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
</my:DataGridTemplateColumn>
</my:DataGrid.Columns>
On btnUpdate_Click event I want to get the value that has been set on ddlNewAgeGroup
But I dont know how to find this Combobox on Button Click Event in WPF. I am using DataTables to Bind grids.
(e.OriginalSource as Button).DataContext should be the object binded to your row, so it should have AgeGroupId property (as seen from ComboBox.SelectedValue), and it's a collection (as seen from ComboBox.ItemsSource). So you may find use AgeGroupName this way:
private void Grid_Click(object sender, RoutedEventArgs e) {
var row = (e.OriginalSource as Button).DataContext as %YourDataType%;
var agegroupname = row.First(item => item.AgeGroupId == row.AgeGroupId).AgeGroupName;
// TODO: do what you need with "agegroupname".
}
PS. Please set ComboBox.SelectedValuePath to something like AgeGroupId: without it, ComboBox.SelectedValue is equal to a whole record, not just Id

Resources