I have a WPF UI, with the following elements:
The checked checkbox is in a DataGridRow.
The rest is in the DataGridRowDetails. (It contains a smaller DataGrid)
What I want to get done is to bind the two (shown by red arrows) checkboxes together, so that when one is checked, the other also gets checked, and vice-versa.
I have already taken a look at these questions:
1) WPF Binding with 2 Checkboxes
But when I try this, the click handlers stop working. (The checkboxes stop working altogether)
2) wpf bindings between two checkboxes
When I use triggers, one checkbox triggers the other, and it inturn triggers the other, and goes on.. UI gets stuck.
Sample of my code:
<DataGrid x:Name="DataGrid1">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="SelectionCheckBox1" PreviewMouseLeftButtonDown="SelectionCheckBox1_PreviewMouseLeftButtonDown"
Loaded="SelectionCheckBox1_Loaded"
IsChecked="{Binding ElementName=HeaderCheckBox1, Path=IsChecked, Mode=TwoWay}">
</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DockPanel LastChildFill="True">
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<CheckBox x:Name="HeaderCheckBox1" PreviewMouseLeftButtonDown="HeaderCheckBox_PreviewMouseLeftButtonDown"
IsChecked="{Binding ElementName=SelectionCheckBox1, Path=IsChecked, Mode=TwoWay}">
</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
</DataGrid.Columns>
</DataGridTemplateColumn>
</DataGrid>
</DockPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
Concern : Because the second Checkbox appears only after the row is selected ( which means the other checkbox is selected), I am unable to find the second checkbox through VisualTreeHelpers also.
Some idea even leading to a possible solution will be much appreciated.
i would suggest 2 way binding them to a property they both can access (somewhere inside the window for example) since with solution 1 you are creating an infinite loop
Checkbox 1: clicked => notify changed
Checkbox 2: changed => update => notify changed
Checkbox 1: changed => update => notify changed
...
You will need to create a property in ViewModel say that property is called IsSelected, then you have to bind both these checkboxes to that Property. And it should have its dataContext as your view model and not an Element.
IsChecked="{Binding IsSelected, Mode=TwoWay}"
If your VM is not data context then you will have to traverse to find VM and then bind to it
Related
I am trying to make a DataGrid in WPF that will display the different properties of the items in a given collection. So far, everything works perfectly, except for one. Here is an image of my DataGrid, which is fully populated just as intended:
And you may already see my problem. Each and every item has a value associated with it, which is properly binded. However, I cannot see the value for any of the items unless I specifically click on that cell. For example:
I want the values to be visible at all times, just like the Name and Default Value Columns, but it is very important that the value, and only the value, is editable from the DataGrid at runtime. Here is the XAML I have in place for the datagrid:
<DataGrid Margin="20" AutoGenerateColumns="False" ItemsSource="{Binding ConfigurationParameterCollection}" Name="MasterListBox" ScrollViewer.VerticalScrollBarVisibility="Visible" SelectionChanged="MasterListBox_SelectionChanged" AlternationCount="2" DockPanel.Dock="Top" HorizontalAlignment="Center" Width="1000" >
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<!-- Begin Problem Area-->
<DataGridTemplateColumn Header="Value">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Value, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<!-- End Problem Area-->
<DataGridTextColumn Header="Default Value" Binding="{Binding DefaultValue}"/>
</DataGrid.Columns>
</DataGrid>
Don't worry about the name of the DataGrid, it used to be a ListBox and I just never bothered to change the name. Everything links up perfectly, I just can't figure out why the TextBox text is not visible.
Any help you can give is much appreciated.
EDIT
I know that I can achieve this with using CellTemplate instead of CellEditingTemplate, but the latter has the feature of only editing on two clicks, but selecting the row otherwise. I want to have this feature, so If there is a way to do that with CellTemplate please let me know. With CellTemplate, I see the boxes at all times:
I want it to be like in the second picture, where the rest of the column appears in style with the datagrid, while the cell I am editing looks like a text box.
Change
DataGridTemplateColumn.CellEditingTemplate
To
DataGridTemplateColumn.CellTemplate
You can specify a display template, and an edit template ...
<DataGridTemplateColumn Header="Value">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Value, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Value, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
After wasting 2 day, I just little understand of wpf datagrid data-binding process.In the Earlier,I want to show combo box in datagrid view column.After googled, i found the way to bind combo in datagrid.Now i got the problem that looks like easy but it make me crazy.
This is Initial state.In this state,Combo box is missing.
After double click the row,it visible.
How can i show combo box in Initial state? Thank You.
There'are two templates used in DataGrid:
CellTemplate
CellEditingTemplate
CellTemplate acts a role of, as you said, initial state, whereas CellEditingTemplate is used when you edit a cell. For instance, DataGridTextColumn is actually looks like this:
<DataGrid x:Name="dataGrid" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding SomeField}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding SomeField}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
In my WPF DataGrid, I have a DataGridTemplateColumn, containing a ComboBox as CellEditingTemplate content:
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
The Bindings in the ComboBox and the TextBlock are irrelevant to this question. The problem arises when the Selection of the ComboBox is changed: The DataGrid doesn't leave the edit mode. I can force this by attaching a SelectionChanged event handler to the ComboBox and forcing myDataGrid.CommitEdit() on the DataGrid. However, having multiple DataGrids means that I want to identify the owning DataGrid of the ComboBox. However, the Parent property is null on the ComboBox inside the SelectionChanged event.
How do I either
determine the owning DataGrid or
automatically leave editing mode in some other way when the selection changed?
I'm converting an event-driven app to MVVM and trying to minimize the code-behind. One of the views has a DataGrid, and I've placed a column in it with a UserControl that implements ICommandSource. When you click the control (a "LinkLabel"), the app should launch a new tab for the bound object of the DataRow. So I've bound the SelectedItem prop of the DataGrid to a corresponding property in the ViewModel. Everything works fine, as long as the user selects the DataRow first and then clicks the LinkLabel. But this isn't typical user behavior.
My question is: How can I get the DataGrid to select the parent DataRow prior to firing the Command? I imagine that's not conceptually what the solution will be, but it (hopefully) gets the point across.
DataGrid
<DataGrid Name="dgPeople" MouseDoubleClick="dgPeople_MouseDoubleClick"
ItemsSource="{Binding CollectionOfPeople}" SelectedValuePath="DatabaseId" SelectedItem="{Binding SelectedPerson}"
AutoGenerateColumns="False" RowHeaderWidth="0" IsReadOnly="True"
ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto"
Grid.Row="1" >
<DataGrid.Columns>
<DataGridTemplateColumn Header="Name" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<view:LinkLabel Content="{Binding FullName}"
Command="{Binding Source={StaticResource vm}, Path=LaunchPersonDetailCmd}"
FontWeight="Normal" VerticalAlignment="Center" Margin="0" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
...
<DataGridTextColumn Header="Job Title" Binding="{Binding JobTitle}"
Width="*" />
<DataGridTextColumn Header="Status" Binding="{Binding Status}"
Width="*" />
...
</DataGrid.Columns>
I can provide other code as needed, but nothing else seems immediately relevant.
Thank you!
There are a few different ways to do this. The view-only way is to use a behaviour that watches for click messages bubbling up the hierarchy and manipulates the visual tree directly, but personally I think it's much better to do it in the view model. I'd need to see your LinkLabel control but if it's anything like the standard WPF controls then it should also have a CommandParameter that you can use to bind to the row data context and pass as a parameter into your command handler.Then it's just a matter of having that handler set the SelectedItem to whatever was passed in.
What I suspect is that your LinkLabel is not actually a necessary control and that it can be replaced with a regular data template containing a templated button that will easily support what you're trying to do, but I'd need more details about what that control actually does.
Recently I asked similar questions here and here, but could not fix the issue properly.
I have a DataGrid with ComboBox that can contain either a selected item or not. But if it does then the ComboBox should select it when the dropdown is opening which is doesn't.
Currently I have this code which works except when opening the dropdown the first time. It is nothing selected.
<DataGridTemplateColumn Header="Company">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.Companies}"
SelectedItem="{Binding Company, Converter={StaticResource NullValueConverter}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Company, Converter={StaticResource NullValueConverter}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
The NullValueConverter prevents exceptions if the Company is null.
If your company was not a string as you mentioned in the comments then it can't display the Name unless you set
DisplayMemberPath="Name" or create an ItemTemplate.
You should use SelectedItem="{Binding
Company,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" to update
the value as soon as it changes because if you don't it will only
raise ProperyChanged when you focus another cell or row.
if your Property was immutable or a value type then you
should use SelectedValue="{Binding Path=Company,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" SelectedValuePath="Content"
.