I know that the data grid isn't designed to directly access each row. My problem is I need to highlight rows based on certain conditions but not just at loading time. After the grid has been loaded there can be changes that occur on a collection that is not the collection that the grid is populated from so changes to this collection obviously won't affect the grid.
Sample Data Diagram:
[GridCollection] [SecondaryCollection]
{ID = 0, Name = "Test A"} {ID = 0, GridCollectionID = 0, Name = "Test A Linked"}
{ID = 1, Name = "Test B"}
So in this case GridCollection item 0 would be highlighted in the grid. But if I add another item to the SecondaryCollection this item would be should highlighted in the grid.
Now I can force an update to the grid's ItemsSource but this seems hacky. Anyone got any ideas on how to approach this issue?
This would be really easy to achieve by using Prism's EventAggregator:
Make sure the items in GridCollection implement INotifyPropertyChanged
Add a boolean IsHighlight property to the class of items in GridCollection
When an item is added to SecondaryCollection, fire an event using the event aggregator, using the GridCollectionID as payload.
Subscribe to this event on GridCollection and set IsHighlight to true.
On the DataGrid, set your conditional format to be on when IsHighlight is true.
This methodology is decoupled and robust and it let's you make the highlight look as you want and change any time, even using animations.
Related
I have a winforms program I am migrating to entity (EF5). The edit works okay. The add does not. The basic workflow is user can either add or edit an object. There is a list of comboboxes, text boxes, etc on screen for the user to input.
I have the entity bound to a binding source. I have the textbox bound to the bindingsource.
Add functionality looks like this.
If (mViewAddEdit = ViewAddEditEnum.Add) Then
Dim ps As New RADS.PHANTOM_SESSION
Me.bsPhantom.DataSource = db.PHANTOM_SESSION.Add(ps)
Me.EdtMuscleWater.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me.bsPhantom, "MUSCLE_OR_WATER", True, DataSourceUpdateMode.OnValidation)) ' etc
End If
So that seems okay, but when user clicks ok button (to save).
drvPhantom = TryCast(Me.bsPhantom.Current, RADS.PHANTOM_SESSION)
' examining the object shows nothing bound.
If mViewAddEdit = ViewAddEditEnum.Add Then
db.PHANTOM_SESSION.Add(drvPhantom)
db.SaveChanges()
End If
The issue arose from the form blocking validation.
Me.AutoValidate was set to disable. So this blocked the binding source from updating even with a call to Me.Validate()
Also since I found it so hard. This is how to Add or Edit - controls bound to binding source using Entity EF5.
If (mViewAddEdit = ViewAddEditEnum.Add) Then
Me.bsPhantom.DataSource = New PHANTOM_SESSION
SetPhantomDataBindings()
Else
Dim query = From ps In db.PHANTOM_SESSION Where (ps.PHNTM_SESSION_NO = CDbl(mPhntmSessionNum))
bsPhantom.DataSource = query.ToList() ' resize occurs here
SetPhantomDataBindings()
...
End If
The other thing is if you are programmatically writing to the text box, ie textbox1.text = "foo" you must also update the underlying object.
CType(Me.bsPhantomBlock.Current, RADS.PHANTOM_BLOCK).OTHER_CORRECTION = CDec(val)
Here we are casting the current object of the binding source to its type (PHANTOM_BLOCK) then setting the field "OTHER_CORRECTION" to val.
Updating the binding source does not work as it causes all inputted user data to be thrown away. For example there are 5 text boxes (a,b,c,d,e). user enters 1,2,3,4,5 into those. The 5th is handled by bindingsource Write: textbox1.DataBindings(0).WriteValue - this will update the 5th field (e),but causes a,b,c,d to be blank as the are reverting to stored value. This is my experience anyway.
There is a djContainer having multiple djtabPane(s).
A combobox is situated on the first djtabPane, having the property: required="true".
but, when I move to next djtabPane in order to complete some other fields, I get the notification that the combobox value is required.
Can I achieve this property of the combobox but only if I want to submit / save the doc.?
<xe:djTabContainer id="djContentPane1" tabPosition="top" doLayout="false">
and the djTabPane ( all are the same, only the title is different ) :
<xe:djTabPane id="djTabPane1" title="Title1">
You'll need to move the validation to your save/submit method. A validator runs whenever a partial refresh happens unless you set immediate="true" or processValidators="false". But I don't think there's a way to set that on any of the in-built tabbed containers.
The advantage of Greg's approach when moving towards an MVC pattern is that the same validation can be run whenever saving the data object, not just from a specific XPage / Custom Control. The down-side is more work coding what's effectively in-built, e.g. tying the validation message back to the relevant component, setting the component's valid property to false etc.
First things first. There's a good chance what I want to do should really be done with VB and not VBA. But as long as it is possible I would rather use VBA.
I have a userform of essentially a big diagram made of hundreds of labels. I want to separate these labels into groups. And then separate these groups into subsystems. The idea being I have some form of heirarchy to work with. The label groups need to change color based on what I have selected in a combo box, and if I click on one of these labels I want to bring up a user form showing details of the subsystem using click events.
I'm pretty sure I need to use multiple classes to do what I want but am fairly new to using class modules. Though I get the concept.
Basically I want some functionality that goes subsystem -> label group( or part) -> color with click events for the whole subsystem and combo box events for changing label group colors.
I saw a thread online about grouping labels or text boxes but it only works to trigger the even for a group, not change the properties of the whole group once the event is triggered. I would like to set this up in classes as well so I can export the system for use in other future userforms.
I was able to create groups of labels and change them together like I wanted:
CPart (Class Module 1):
*This is meant to handle the event triggering of the labels and includes some color code that I used to test functionality of the groups changing together and functionality of changing colors.
Public WithEvents trigger As MSForms.Label
Dim pLabels As Collection
Property Set triggers(c As Collection)
Set pLabels = c
End Property
Private Sub trigger_Click()
For Each obj In pLabels
obj.BackColor = RGB(255, 0, 0)
Next obj
End Sub
CTrigger (Class Module 2):
*This took a collection of labels which were passed in through a collection variable in the userform and then stored each label as a trigger in a separate class variable, along with the whole collection of labels in that group. This way when any trigger fires the event, all of the labels change.
Dim CTrigger() As New CPart
Dim pLabels As Collection
Dim i As Integer
Property Set Labels(c As Collection)
Set pLabels = c
For i = 1 To pLabels.Count
ReDim Preserve CTrigger(1 To i)
Set CTrigger(i).trigger = pLabels.Item(i)
Set CTrigger(i).triggers = pLabels
Next i
End Property
Property Get Labels() As Collection
Labels = pLabels
End Property
I really don't like the way it works, partly because I am losing myself in the logic of it constantly, and partly because it means that in order to use this I have to make collections of labels in the userform module anyway just to run it. It is very inefficient code, but I am putting it up so you get an idea of what I am trying to accomplish.
What I would much rather do instead is have one class variable to hold my custom collection of labels (a "LabelGroup"). Another class variable is likely required to hold the labels themselves (I think). And then all I would have to do is go through and write methods for the LabelGroup class such as changecolor, and it could handle that. But I can handle that part, for now what I really need help with is setting up the class framework in a neat way, so that the module I will eventually run could just say things like:
LabelGroup1.Add Label1
LabelGroup2.Add Label2
or
Private Sub button_click()
LabelGroup1.ChangeColor(RGB(...))
End Sub
These two articles have been helping me along:
http://www.databaseadvisors.com/newsletters/newsletter200503/0503usingcustomcollections/using%20custom%20collections%20in%20microsoft%20access.asp
http://j-walk.com/ss/excel/tips/tip44.htm
I was just looking at something similar but not quite so detailed. I'm trying to improve the look of a complex userform by making it look more modern and was going to try to fake mouseOver highlighting or at least active/inactive shading for labels placed overtop of graphical buttons.
Anyway, have you considered just changing the names of the label objects so that they are prefixed/suffixed with some kind of group or subsystem ID?
That way when you pass them to a sub to change their colour, you can check the prefix or suffix.
Background:
Hello everyone, I'm not new to visual basic or programming. I just find it the fastest to make a GUI in visual basic for various programs; however, I'm having a recent issue.
I have a form with a ListView control that I populate using a textbox and a button.
the code I use for the button is:
Code:
listview1.items.add(textbox2.text)
Pretty simple code that has always worked. I changed a few properties on my ListView as well, and I will list them. I just don't know what is going on.Here's a list of the properties changed (everything else is default):
Properties:
BackColor = DarkGray
BorderStyle = FixedSingle
HeaderStyle = None
MultiSelect = False
View = Details
All properties were changed via the properties tab and not through code. I want to be able to add text to the control. I'm not adding any subitems either. I'm just confused because this code has always worked, and I've never had this issue. I'm also using Visual Basic 2010 Express Edition if that helps.
If the added item in ListView is not displaying then check the ListView.View property. if this property has set to Detail view then Columns must be added in that listView control otherwise added item will not display.
Make sure item is added correctly.
Dim item As ListViewItem = listView1.Items.Add("Item Text") ' This text will be displayed in first column. The column index will be 0
' Further values will be added in SubItem
item.SubItems.Add("Sub Item1")
item.SubItems.Add("Sub Item2")
item.SubItems.Add("Sub Item3")
I have a simple VB.NET 2008 app that helps users to edit fields in the database. Simple enough as a first "real" project in .NET, right?
For one table, I am currently using a DataGridView so it can be edited straight up. However, instead of offering the user the entire table, I'd like to group the data by the 'CompanyNumber' column and use a navigator to page through. In other words, I'd like the DataGridView to show me all the lines related to one company, then click the "next" arrow to show the next company, etc.
(I know I could do this with Xceed DataGrid, but I'm using Windows Forms not WPF, and I'd really prefer to do this with "pure" ADO.NET for this project.)
Update 2009-09-28:
So I have created a ComboBox filled from the same BindingSource, and configured its SelectedIndexChanged to change the Filter value on the DataGridView.
But still, filling the ComboBox--which should be easy!--continues to be a problem. I can either:
(a) fill it from the BindingSource, in which case I see multiples of each 'CompanyNumber' and I can't figure out a way to show only distinct values, or
(b) create another TableAdapter in the data source which is just a "Select DISTINCT CompanyNumber..." query, which mostly works, except that that first value of the list changes when I change the selection (e.g. if the ComboBox shows "100, 101, 102, 103" and I pick "102", then the list will show as "102, 101, 102, 103").
Any recommendations?
(Also, bonus if you can suggest how to make the BindingNavigator's arrows page through the 'CompanyNumber' filters instead of the items in the DataGridView... which is what I'd really like to see.)
What you could do is just force the DataGridView to sort CompanyName, this way all rows with the same company name are next to each other and the user can navigate the data grids with the paging that comes with it.
Alternatly, you could follow through with your combobox/DropDownList idea, which would be best. From what I understand when you select an item in the combobox everything in it changes?
Another way is to create two separate buttons, "Previous" "Next", that when clicked, will change the DataGridView's binding source to only show a certain company. You would need to store an array of company names, then store what the current DataGridView's binding source is displaying.
I ended up figuring it out myself, and the solution is clean and simple. Here are the basic steps:
create a DataView off of the table out of the DataSet
use the DataView.ToTable() method to create a new table filtered to only distinct values from the needed column ('CompanyNumber')
create a BindingSource which uses the new DataTable as its DataSource
bind the ComboBox to the new BindingSource
bind the BindingNavigator to the new BindingSource
Because the ComboBox and the BindingNavigator use the same BindingSource, they will update each other with the changes automagically.
Here's the rough code:
Private Sub CoNumsComboxBox_LoadData()
Dim dvCoNums As DataView, dtCoNums As DataTable
dvCoNums = New DataView(Me.ODBCDataSet.Tables("CompanyFundProfile"))
dvCoNums.Sort = "CompanyNumber ASC, FundNumber ASC"
dtCoNums = dvCoNums.ToTable("CompanyFundProfile", True, "CompanyNumber")
CoNums_BindingSource.DataSource = dtCoNums
CoNumsComboBox.DataSource = CoNums_BindingSource
CoNumsComboBox.DisplayMember = "CompanyNumber"
CoNumsComboBox.ValueMember = "CompanyNumber"
'attach handler which changes DataGridView1's filter when this changes
AddHandler ToolStripComboBox1.SelectedIndexChanged, AddressOf CoNumsComboBox_SelectedIndexChanged
CompanyFundProfile_BindingNavigator.BindingSource = CoNums_BindingSource
End Sub