WPF DataGrid cells select content text - c#

I have a WPF project with a DataGrid in my window and, initially, I just set its ItemsSource to a collection of objects, and the grid auto-generated columns, based on their properties. In that stage when starting the application I, as the user, could click a cell (in the user interface) and it would allow me to select/drag-select part of the text in that cell.
Now I disabled the auto-generation of columns and defined custom columns, binding them to select properties of said objects. And now clicking a cell just selects the entire cell and its entire contents. I've looked at all DataGrid and DataGridCell properties but don't see anything which would obviously alter this behaviour.
How can I set a manually defined DataGridTextColumn in the XAML to have the text content of its cells be partially selectable, instead of only being able to select the entire cell content?

The DataGridTextColumn is behaving the same whether it is autogenerated or not. Maybe you are setting IsReadOnly = True. That could be one reason for it to behave like you are describing. Otherwise, you have to provide us with code and data, that is showing your case.

I want to thank RolandJS, his answer made me realise I probably could inspect WPF controls' properties at debug time and that led me to the Live Visual Tree, seeing all properties are the same, which led me to the binding, which was mode = one way.
So, basically, the text in DataGrid cells can only be partially selected/drag selected if the binding is in a mode that allows changing the source, because that is what you are potentially doing.

Related

Why are some properties unaccessable

I was trying to get the text that I wrote in a DataGrid cell after editing it, so I put a breakpoint in the function CellEditEnding and looked at the EventArgs and noticed that it contains the property "Text", so I wouldn't have to do the usual XAML binding hacks to get it.
However, I quickly noticed that it will not let me access it.
After taking a look at the FrameworkElement class, I can confirm that there is no Text property, so what is going on, why can't I acces the property?
why can't I acces the property?
Because a FrameworkElement indeed has no Text property.
TextBox, which derives from FrameworkElement, has a Text property though so you could cast the EditingElement to a TextBox and then access the property:
string text = (e.EditingElement as TextBox)?.Text;
Visual Studio displays the properties of the actual object in memory.
It's a bad idea to use the UI as a data store and try and directly work with it.
You should bind an observablecollection of t to the itemssource of your datagrid and work with each instance of t.
That will be far easier to work with.
As to why are some properties inaccessible?
It's because those properties aren't where you think they are. The DatagridCell has a series of things nested within it.
DataGridCell > Border > ContentPresenter > TextBlock
Download snoop https://github.com/snoopwpf/snoopwpf or install using chocolatey / your preferred method.
Run snoop.
Run your app.
Drag the right gunsight thing over you window.
A window should open up with two panels. Controls and properties.
Mouse over a datagrid cell.
press shift+ctrl and you should see the element under the mouse selected in the ui tree.
A datagrid is pretty complicated and there are multiple things in each row.
See that textblock there?
That's the thing has a text property.
Or at least that's the thing when you're not in edit mode.
Switch to edit mode and I have a TextBoxView.
So one complication is, which are you working with at a given time?

Multiple combo boxes bound to same source with conditional visibility on items

Unlike many questions related to this, I'm not having an issue with all combo box values being changed at when changing one combo box selection.
My problem is that I want to change the visibility of certain items when they are selected in the other list. I have two input port combo boxes and when I select port 5, say, on the first one, I want port 5 to not appear in the drop down for the second combo box.
I've tried this solution How to set combox item visibility? as it looked very promising but it won't let me cast from string to ComboBoxItem in the code-behind.
What else am I to do? I thought of creating a style in the XAML itself, but I can't quite figure out the conditions to use within the XAML and can't seem to find any topics over it. Lastly, I also have conditions in the setters for my input properties to check that the value the port is being set to is not the same as the other port, but it's not seeming to do anything for the view.
Are you using an ObservableCollection? This would allow for two way data binding whereas your UI will reflect the contents of each ObservableCollection in realtime if added to or removed from in an event. In another scenario, I had to apply a custom object to bind to in order to determine whether or not to show it, however, it was not the contents of a combobox, which are harder to access.

Switching column and row headers in DataGridView

I have set up a DataGridView in part of my application as shown in the following screenshot:
I'm attempting to databind this to a specified business object, and use it as an alternative PropertyGrid (there are a number of issues that make PropertyGrid inappropriate for my planned use).
The below view is built on-the-fly from a specified set of the business object's properties.
There are three area's I'm struggling with:
DataBinding - I want to bind this grid to a specified business object, for two-way databinding.
CellTemplate - I will need to have different cell templates on different rows, depending on the datatype of the property. TextBoxes, ComboBoxes, CheckBoxes, Date/Time Pickers.
Validation - OnCellLeave, I need to validate the value entered, and format the cell red = failed validation, blue = passed validation. Then when the user leaves the overall control, if there are blue cells, persist the object to DB, but if there are red cells, restore the object from DB. I already have this functionality implemented on other (traditional) DataGridView's, and this description is just for info / context.
I have implemented all of the above in the traditional form (properties in column headers), but am having problems getting it working with the properties in the row headers, which is what I'm really after.
If anyone has implemented something like this, or can help, it would be much appreciated. Thank you.

WPF Show Data in Grid

I have a C# CLI program that scans for missing Windows updates and writes them to command line or serializes them to XML depending on the flag passed in. I'm trying to build a WPF component to this but am unsure of a few things. Specifically I'd like to write all missing updates to a grid in the center of my WPF main window. The appearance would be something like this (with gridlines between the fields):
NAME SEVERITY DETECTED
Security Update for Windows 7 (KB1234567) Important 3/9/2014
Security Update for Windows 7 (KB7654321) Critical 3/9/2014
My specific questions:
What type of control would I need to add to the window to house this data?
How do I send the data (detected missing update names and properties) to the grid for display?
How can I set the control so that it is collapsed (or invisible) when no missing updates are detected?
Will I need to add a scrollbar to the grid or will one display automatically?
Apologies for the simple questions. I'm really just looking for some examples to get started, and I haven't been able to find anything thus far that meets my needs.
What type of control would I need to add to the window to house this
data?
DataGrid control is what you are looking for.
How do I send the data (detected missing update names and properties)
to the grid for display?
Bind ItemsSourceof DataGrid to ObservableCollection<T> where T will be class containing data with properties Name, Severity and Detected.
How can I set the control so that it is collapsed (or invisible) when
no missing updates are detected?
Add a DataTrigger to check if ItemsSource collection contains no data, collapse the visibility.
Will I need to add a scrollbar to the grid or will one display
automatically?
DataGrid internally use ScrollViewer. No need to add explicitly.
Refer to the dataGrid samples here and here.
As an alternative DataGrid can offer ListView control, it will be little "easier" than the DataGrid, he also supports the ability to sort columns. For him also need to bind a ItemsSource collection to display:
The ListView control provides the infrastructure to display a set of data items in different layouts or views. For example, a user may want to display data items in a table and also to sort its columns.
Example in MSDN.
Little add some notes to the wonderful answer of #RohitVats, all that has been said about DataGrid also applies to ListView:
How can I set the control so that it is collapsed (or invisible) when no missing updates are detected?
In this situation, I advise you to adhere to the principle of MVVM. Use Binding and Commands to create an independent application. You want to create property (for example IsEnabled) in Model / ViewModel and use bindings to set them in the View, in order to avoid apply directly to the Control. WinForms style app or "regular" applications creates a strong connection between logic and UI, which subsequently impedes further change and application maintenance.

How do I add additional data to a DataGridRowGroupHeader?

I have a DataGrid that is showing some data via a PagedCollectionView with one group definition. I have created a Style for the corresponding DataGridRowGroupHeader under which I have added a ControlTemplate containing an additional TextBlock and a spacing Rectangle. I would like to bind the widths of these controls to the widths of particular columns, but I am struggling to get this working. I would also like to bind the Text property of the TextBlock to a value.
I tried binding the widths via the Width property of a Rectangle in resources but this didn't work (possibly because the Rectangle was never drawn and therefore didn't calculate it's layout).
However, I believe both sets of bindings can be performed with some use of one or more ValueConverter implementations, but I was wondering if there was a better way. Can any of this be achieved through the definition of a ControlTemplate?
After some trial and error I was able to customize my row group headers. The key to unlocking the solution involved both the RowGroupHeaderStyles property and the LoadingRowGroup event on the DataGrid.
By defining one or more styles for the groups, I was able to customize the control template to include additional named elements. I then used the event to gain access to those elements and either set or bind the relevant values to show the information I required. The only stumbling I had related to binding the size of controls, which I eventually worked around by saving a reference to each row and setting those sizes when it was necessary to refresh them rather than relying on bindings. This may be specific to my project so your mileage may vary.
Update
JDM asked how you get the controls to perform binding etc. in the LoadingRowGroup event handler. You can get the row header from the DataGridRowGroupHeaderEventArgs.RowGroupHeader property of the event arguments and then use the VisualTreeHelper to get the child controls of the header. Once you have the controls, you can bind to them in code as you would any other control.

Categories