WPF how to retrieve binded property in code behind - wpf

In my legacy project I need to get the binding property name via code behind. The XAML:
<DataGridTextColumn MinWidth="180" MaxWidth="180" Width="Auto" Binding="{Binding ConfigObject.MAC_Descr}" Header="Descr" Foreground="Black">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="Padding" Value="6,12" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsDirty}" Value="True">
<Setter Property="TextBlock.Background" Value="{StaticResource IsDirtyColor}" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
<DataGridTextColumn.EditingElementStyle>
<Style TargetType="TextBox">
<Setter Property="Background" Value="White"/>
<Setter Property="Padding" Value="5,12"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>
The event I use:
private void Row_DoubleClick(object sender, MouseButtonEventArgs e)
{
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{
DataGridCell row = sender as DataGridCell;
if (row == null) return;
// Binding column name??
string bindingExpression = row.GetBindingExpression(TextBlock.TextProperty).ResolvedSourcePropertyName;
}
}
Basically in the case above I need to retrieve the "MAC_Descr". Any help?

You could try something like this:
private void OnCellDoubleClick(object sender, MouseButtonEventArgs e)
{
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{
if (!(sender is DataGridCell cell)) return;
if (!(cell.Column is DataGridTextColumn column)) return;
if (!(column.Binding is Binding binding)) return;
var path = binding.Path.Path;
}
}

Cast the Content of the cell to a TextBox or TextBlock depending on whether the cell is editable:
DataGridCell row = sender as DataGridCell;
if (row == null) return;
TextBox textBox = row.Content as TextBox;
if (textBox == null) return;
string bindingExpression = textBox.GetBindingExpression(TextBox.TextProperty)
.ResolvedSourcePropertyName;

Related

How to hightlight a datagrid cell in wpf

I am having a datagrid,in that i have to highlight a particular cell based on a particular condition.
Below is the code snippet.
if (plannedOrderDetail.ORDER_TYPE == OrderType.Emergency || plannedOrderDetail.ORDER_TYPE == OrderType.Warning)
{
e.Record.FieldLayout.Fields[6].Settings.CellPresenterStyle = ApplicationEx.GetResource<Style>("HighLightCellStyle");
}
This code highlights all the cells in the 6th column.How can i highlight the particular cell.
If ORDER_TYPE is accessible via the row's data context, you could use a style trigger, approximately like this:
<DataGrid...>
<DataGridTextColumn x:Name="theSixthColumn" ...>
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
...
<Style.Triggers>
<DataTrigger Binding="{Binding ORDER_TYPE}"
Value="Emergency">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding ORDER_TYPE}"
Value="Warning">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid>
First get Specific DataGridCell from DataGridRow, then apply Style.
Below is extension for get DataGridCell from row by column index:
public static DataGridCell GetCell(this DataGridRow row, int column)
{
if (row != null)
{
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(row);
// try to get the cell but it may possibly be virtualized
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
return cell;
}
return null;
}

Issue with Tab navigation in WPF noneditable Combobox

I have a WPF combobox...which is non-editable. When I tab into this combobox...I have a style setter (<Setter Property="IsDropDownOpen" Value="True"/>) to open the combobox. But when I tab again..the focus move to next item in the opened combobox....and it cycles over there. I am not able to tab out to next control.
What is wrong here?
Thanks
Try :
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsTabStop" Value="False"/>
</Style>
Or
Work with KeyboardNavigation :
WPF tab order with custom controls?
Not recommend, but works...
<Grid>
<ComboBox Grid.Row="1" Margin="0,0,0,0" Name="comboBox1" HorizontalAlignment="Left" Width="120" Height="20" IsEditable="False" KeyDown="comboBox1_KeyDown" GotKeyboardFocus="comboBox1_GotKeyboardFocus" >
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsDropDownOpen" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
<ComboBoxItem>Male</ComboBoxItem>
<ComboBoxItem>Female</ComboBoxItem>
<ComboBoxItem>Unknown</ComboBoxItem>
</ComboBox>
</Grid>
private void comboBox1_KeyDown(object sender, KeyEventArgs e)
{
ComboBox cb = sender as ComboBox;
if (e.Key == Key.Tab && cb.IsDropDownOpen)
{
ComboBoxItem item = FocusManager.GetFocusedElement(Window.GetWindow(this)) as ComboBoxItem;
cb.SelectedItem = item;
cb.IsDropDownOpen = false;
e.Handled = true;
}
}
private void comboBox1_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
ComboBox cb = sender as ComboBox;
cb.IsDropDownOpen = true;
}
You can achieve the same by the following code:-
private void comboBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
IsDropDownOpen = true;
e.Handled = true;
}
}
Now when focus will set on ComboBox then you need to hit enter to open drop down and you can use down key word to traverse ComboBox items.
To move to the next control,you need to press tab.
I had the same problem, solved it like this in XAML:
<Style x:Key="RadComboBoxItemStyle" TargetType="telerik:RadComboBoxItem">
<Setter Property="Focusable"
Value="False" />
<Setter Property="IsHitTestVisible"
Value="True" />

MultiBinding And MultiTrigger

...So I have 2 elements, i want that the IsChecked property of the checbox will binded to my
'IsAlwaysOn' property which is in my My Class object(Two Way), and to an element combox selected value properties, where if the value is 'enter', then IsChecked is false,
any ideas?
You can do this with a DataTrigger, however I wouldn't recommend it because the value of the CheckBox would not always get saved to MyClass.IsAlwaysOn
<Style x:Key="MyCheckBoxStyle" TargetType="{x:Type CheckBox}">
<Setter Property="IsChecked" Value="{Binding IsAlwaysOn}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MyComboBox, Path=SelectedValue}" Value="Enter">
<Setter Property="IsChecked" Value="False" />
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style>
Instead, I would recommend handling this in the PropertyChange notification in MyClass. To prevent changes, I would either include a property in MyClass which determines if the CheckBox can be changed or not, or disable the CheckBox in a trigger like above.
void MyClass_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "SelectedComboBoxItem")
{
if (SelectedComboBoxItem == "Enter")
{
IsAlwaysOn = false;
CanChangeCheckBox = false;
}
else
{
CanChangeCheckBox = true;
}
}
}

How to add a right click context menu to Column Header for a WPF 4 DataGrid?

I want the context menu for a DataGrid's column headers to be different than the rest of the cells. So using the regular ContextMenu property is not going to work. There is DataGrid.RowHeaderTemplate, but I can't find DataGrid.ColumnHeaderTemplate.
Edit/Note: Columns are generated dynamically.
Target a common Style to all DataGridColumnHeaders:
<DataGrid.Resources>
<ContextMenu x:Key="DataGridColumnHeaderContextMenu" ...>
</ContextMenu>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="ContextMenu"
Value="{StaticResource DataGridColumnHeaderContextMenu}" />
</Style>
</DataGrid.Resources>
If you want different context menus for different column headers then use triggers:
<DataGrid.Resources>
<ContextMenu x:Key="ColumnHeaderContextMenu1" ...>
</ContextMenu>
<ContextMenu x:Key="ColumnHeaderContextMenu2" ...>
</ContextMenu>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Style.Triggers>
<Trigger Property="Content" Value="Column1">
<Setter Property="ContextMenu"
Value="{StaticResource ColumnHeaderContextMenu1}" />
</Trigger>
<Trigger Property="Content" Value="Column2">
<Setter Property="ContextMenu"
Value="{StaticResource ColumnHeaderContextMenu2}" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
Hope that helps.
It depends on how you are generating your columns, if you are defining them in XAML then you could do this:
<DataGrid DataContext="{Binding MyDataContext}" ItemsSource="{Binding MyItems}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Age}" Header="Age" >
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{TemplateBinding Content}" >
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Task _1" />
<MenuItem Header="Task _2" />
<MenuItem Header="Task _3" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
If you want this to be done fully on code behind below is the approach.
using System.Windows.Controls.Primitives;
private void dgFormat_PreviewMouseRightButtonDown(object sender,
MouseButtonEventArgs e)
{
ContextMenu cm = new ContextMenu();
MenuItem miOne = new MenuItem();
miOne.Header = "One";
miOne.Click += MiOne_Click;
MenuItem miTwo = new MenuItem();
miTwo.Header = "Two";
miTwo.Click += MiTwo_Click;
cm.Items.Add(miOne);
cm.Items.Add(miTwo);
dgFormat.ContextMenu = cm;
dgFormat.ContextMenu.Visibility = Visibility.Collapsed;
DependencyObject depObj = (DependencyObject)e.OriginalSource;
while (depObj != null &&
!(depObj is DataGridColumnHeader))
{
depObj = VisualTreeHelper.GetParent(depObj);
}
if (depObj == null)
{
return;
}
if (depObj is DataGridColumnHeader)
{
DataGridColumnHeader colHeader = depObj as DataGridColumnHeader;
if (colHeader.Content.ToString() == "First Name")
{
dgFormat.ContextMenu.Visibility = Visibility.Visible;
}
}
}
private void MiOne_Click(object sender,
RoutedEventArgs e)
{
MessageBox.Show("One");
}
private void MiTwo_Click(object sender,
RoutedEventArgs e)
{
MessageBox.Show("Two");
}

How to highlight a gridview row if some object value is greater than another?

would like to know how to highlight a gridview row if some object value is greater than another ? (Consider the gridview to be bind to an observablecollection)
Thanks.
Put a property on the class of the items in your observable collection that will get set to true/false based on the comparison you need. Then you should be able to bind to this property in a DataTrigger for a Style on the DataGrid's ItemContainerStyle.
Try this...
<DataGrid ItemsSource="{Binding YourObservableCollection}" >
<DataGrid.ItemContainerStyle>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding YourShouldHighlightProperty}" Value="True">
<Setter Property="Control.Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.ItemContainerStyle>
</DataGrid>
You will need to implement a converter to do a > comparison but this shows a highlight
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsParent}" Value="True">
<Setter Property="Background" Value="Gainsboro" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
Use the following code.It wored for me.
private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
try
{
foreach (loadtodatagrid item in gridview.ItemsSource)
{
var row = gridview.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (item.item1== item.item2)
{
row.Background = new SolidColorBrush(Colors.Yellow);
}
else
{
// row.Background = new SolidColorBrush(Colors.Green);
}
}
}
catch(Exception ep)
{
//do nothing....
}
LoadingRow="DataGrid_LoadingRow" to datagrid in WPF

Resources