I have a page with two controls on it, a datagrid and a dataform.
In the datagrid, I have a list of all the objects of a certain class. When a user selects an item in the datagrid, the dataform is loaded with the selected object.
dataForm.CurrentItem = view.CurrentItem;
view is a PagedCollectionView which contains only the selected item.
My problem is, when setting the dataform's currenitem property, if I use just the PagedCollectionView (view) without .CurrentItem, I lose the validation on the dataform. All the required fields are not seen as required. If I use the pcv.CurrentItem as my dataform's CurrentItem validation works fine, but then another issue arrises.
When I use the PagedCollectionView's current item as the dataform's current item:
A user selects an item in the datagrid and the object is loaded fine in the dataform. If a user changes a certain value in any of the textfields on the dataform and then selects a different item to load the dataform with, the following error is thrown:
"Cannot change currency when an item has validation errors or it is being edited and AutoCommit is false. Set ItemsSource to a ICollectionView to manage currency instead."
I am not using the paging properties of the dataform and I have my own save button on the form.
I would appreciate any help, this is my first silverlight project that I am working on.
Edit- I used dataform.CommitEdit when changing the dataform's currentitem. One thing that this did not resolve is if there is a validation error on the form, the currency error is thrown. Is there anyway to bypass this. AutoEdit is true and AutoCommit is false for the dataform
It's a bit hard to determine exactly what's going on here without a sample, but here's an observation that may help resolve the problem. Try instead to bind the ItemsSource property of both the DataGrid and the DataForm to the collection view, and don't bind the DataForm's CurrentItem property. They're magically kept in sync (the selected item in the DataGrid will set the current item in the DataForm) - this is a feature of the CollectionView. This may or may not solve your problem, but either way it won't hurt :).
Blatant self promotion: this and other features of the CollectionView are covered in my book Pro Business Applications with Silverlight 4 :).
I had this problem a lot of times. And always in case add new item.
After few frustrating days I downloaded source codes of Silverlight toolkit.
(You could find in Programs FIles directory (Mine were is C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Toolkit\Apr10\Source) )
Compile and reference instead of assembly System.Windows.Controls.Data.DataForm.Toolkit
In Debug mode we see strange behavior in DataForm.cs:
private static void OnCurrentItemPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataForm dataForm = d as DataForm;
if (dataForm != null && !dataForm.AreHandlersSuspended())
{
if (dataForm._lastItem != null && dataForm.ShouldValidateOnCurrencyChange)
{
dataForm.ValidateItem();
}
if ((!dataForm.AutoCommitPreventsCurrentItemChange && dataForm.IsItemValid) &&
(e.NewValue == null ||
dataForm._collectionView == null ||
dataForm._collectionView.Contains(dataForm.CurrentItem)
))
{
dataForm.SetUpNewCurrentItem();
dataForm.GenerateUI(true /* clearEntityErrors */, true /* swapOldAndNew */);
dataForm.UpdateCurrentItem();
SetAllCanPropertiesAndUpdate(dataForm, false /* onlyUpdateStates */);
dataForm._lastItem = dataForm.CurrentItem;
dataForm.OnCurrentItemChanged(EventArgs.Empty);
}
else
{
dataForm.SetValueNoCallback(e.Property, e.OldValue);
throw new InvalidOperationException(string.Format(Globalization.CultureInfo.InvariantCulture, System.Windows.Controls.Data.DataForm.Toolkit.Resources.DataForm_CannotChangeCurrency, "AutoCommit", "ItemsSource", "ICollectionView"));
}
}
}
dataForm._collectionView.Contains(dataForm.CurrentItem) returns false even the same object exists in dataForm._collectionView
I changed conditional:
if ((!dataForm.AutoCommitPreventsCurrentItemChange && dataForm.IsItemValid) &&
(e.NewValue == null ||
dataForm._collectionView == null ||
dataForm._collectionView.Contains(dataForm.CurrentItem) ||
dataForm.CurrentItem == e.NewValue
))
And DataForm started work fine. Without exception and mistakes.
private void DataForm_EditEnding(object sender, DataFormEditEndingEventArgs e)
{
if (e.EditAction == DataFormEditAction.Commit)
{
...
}
else
{
DataForm1.ValidationSummary.Errors.Clear();
}
}
Check for any validation error when you are binding the current item, if you have any then clear them BindingItem.ValidationErrors.Clear(); then bind the item to dataform.
Related
I have a TFS work item field that seems to exist for most work items, but sometimes doesn't.
I'm attempting to bind these workitems in a listview using a WorkItemCollection, and everything works except when I attempt binding that field.
The field itself is specified in the query select and gives no error. However the only way to get the field without throwing an error on some workitems is as so (in the .cs)::
foreach(WorkItem w in queryResults)
{
if (w.Fields.Contains("Symptom"))
{
w.Fields["Symptom"].Value.ToString();//show
}
}
as these workitems are in readonly mode, I can't just force write the value etc.. (unless I return a Dictionnary with the value paired with the workitem, but I don't think that would be the best solution...)
What I'm attempting to do is in the Listview ItemTemplate, something like this::
<div class="details">
<%# Server.HtmlEncode(Eval("Fields.Contains(\"Symptom\")? Fields[\"Symptom\"].Value : \"\";").ToString())%>
</div>
But I get the 'Contains' is not a valid 'Fields' property (because its a collection method) - I'm stuck with the eval
How can I properly evaluate and display my Symptom field?
If you use TFS 2015 or VSTS, you can use REST API to get Symptom field. The API look like:
GET http(s)://{instance}/DefaultCollection/_apis/wit/workitems?ids=xx&fields=Microsoft.VSTS.CMMI.Symptom&api-version=1.0
Or with .net Api:
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.Client;
using System;
namespace TestCaseProject
{
class Program
{
static void Main(string[] args)
{
var tfs =
TfsTeamProjectCollectionFactory.GetTeamProjectCollection(
new Uri("http://tfsserver:8080/tfs/CollectionName"));
var service = tfs.GetService<WorkItemStore>();
var wi = service.GetWorkItem(id);
foreach (Field field in wi.Fields)
{
Console.WriteLine("{0}: {1}", field.Name, field.Value);
}
}
}
}
Use OnItemDataBound
Nothing seemed to work directly on the page so I moved away from that approach and went with attempting to solve my problem in the codebehind, since I was already capable of sorting it out on that front.
I removed my sourceObject from my page and instead had the codebehind programmatically databind my listview. (this step is not necessary)
TFSListView.DataSource = SearchHandler.SearchTFS(searchstring);
TFSListView.DataBind();
Then I used OnItemDatabound event to be able to manage each item being bound, I check if that annoying symptom field exist for the dataitem being bound and fill up the appropriate control if it does (all this replaces one eval line, so I'm still a bit annoyed but it didn't seem to be possible directly in the aspx page)
protected void TFSListView_ItemDataBound(object sender, ListViewItemEventArgs e)
{
ListViewDataItem myitem = (ListViewDataItem)e.Item;
if (e.Item.ItemType == ListViewItemType.DataItem)
{
Control divDetails = e.Item.FindControl("divLsvDetails");
WorkItem myWI = myitem.DataItem as WorkItem;
if (myWI != null && divDetails != null)
{
if (myWI.Fields.Contains("Symptom"))
{
((HtmlGenericControl)divDetails).InnerHtml = myWI["Symptom"].ToString();
}
}
}
}
I have a SharePoint list where I register a custom ItemUpdating event receiver but I am seeing some really strange behavior in this solution. This behavior occurs if I add any code to the event receiver other than base.ItemUpdating.
What happens is if I debug the event receiver I can see that properties.AfterProperties has all the values entered on the field and properties.ListItem has the original item. But once the ER finishes running and the page reloads nothing is saved and it just returns to what it was before I changed values. Even more weird, if I go and manually set the after properties similar to below it works and the updates are saved correctly. So basically the event receiver is making me responsible to do any changes to the item but this is not normal behavior for ItemUpdating. Does anyone have any idea what might cause this?
public override void ItemUpdating(SPItemEventProperties properties)
{
var recurringBefore = properties.ListItem.TryGetValue<bool>(Constants.CommonFields.Recurring_STATIC);
var recurringAfter = Convert.ToBoolean(properties.AfterProperties[Constants.CommonFields.Recurring_STATIC]);
//This loop is the horrible fix I have done to manually update the relevant fields but this shouldn't be necessary
var item = properties.ListItem;
foreach (SPField key in item.Fields)
{
if (item[key.InternalName] != properties.AfterProperties[key.InternalName] && key.CanBeDisplayedInEditForm && properties.AfterProperties[key.InternalName] != null)
{
//looping through and setting the AfterProperties to what they already are makes them save? If I don't do this nothing saves
properties.AfterProperties[key.InternalName] = properties.AfterProperties[key.InternalName].ToString();
}
}
if (!recurringBefore && recurringAfter &&
currWfStatus == Constants.WorkflowStatus.Processed)
{
//do some stuff
}
base.ItemUpdating(properties);
}
Is it because you are not saving current item at all, something like this:
item.update();
I am making myself a project manager and I need to refresh Project List every so often. When I am refreshing the Project Manager, I want to select the item that was previously selected. But that selection causes my text box to unselect, therefore, what happens is that that text box unselects after typing one key.
So outline what happens:
I try to edit one text box
Edition causes update in project -> program calls RefreshProjectList()
RefreshProjectList() on marked position causes selected text box to unselect
Result: You must select text box after writing one symbol
Picture if useful
These selected text boxes are struggling to be edited
Code:
private void RefreshProjectList() {
if (BlockListReload)
return;
Project selected = (Project)ProjectList.SelectedItem;
ProjectList.Items.Clear();
CurrentlyShown.Clear();
foreach(Project p in Projects){
if (p.state == State.Planned && ShowPlanned.Checked) {
CurrentlyShown.Add(p);
ProjectList.Items.Add(p);
}
if (p.state == State.Active && ShowActive.Checked) {
CurrentlyShown.Add(p);
ProjectList.Items.Add(p);
}
if (p.state == State.Finished && ShowFinished.Checked) {
CurrentlyShown.Add(p);
ProjectList.Items.Add(p);
}
if (p.state == State.Delayed && ShowDelayed.Checked) {
CurrentlyShown.Add(p);
ProjectList.Items.Add(p);
}
}
if (selected == null)
return;
if (ProjectList.Items.Contains(selected)) {
ProjectList.SelectedItem = selected; // IF I REMOVE THIS
} else {
if (ProjectList.Items.Count > 0)
ProjectList.SelectedIndex = 0; // OR THIS LINE, EVERYTHING WORKS
}
}
If you need more code, I will be happy to provide, but I don't want to spam you with loads of unuseful code.
Q: Why does changing selected item in ListBox cause deselecting of TextBox and how to prevent it?
Several controls that have selectable text or items also come with a property HideSelection.
This includes:
TextBox
RichTextBox
ListView
but not
ListBox
CheckedListBox
DataGridView
Like it or not it always defaults to true so the selection is hidden whenever the focus is off the control..
Simply set it to false in the designer and you can see all selection no matter where the focus is..
OMG. I honestly don't know why I did not see it.
ProjectList.SelectedItem = selected;
//where ProjectList is ListBox<Project> and selected is Project
I am selecting an item in the ProjectList(ListBox). I didn't realize that it was calling a ProjectList_SelectedIndexChanged() event which was doing it.
EDIT: SOLVED by adding this:
if (focused != null) {
this.ActiveControl = focused;
focused.Select(focused.TextLength,0);
}
Where focused is a TextBox I set to last selected TextBox and this is the form.
Thanks TaW.
I'm using listview that must be able to cope with multiselection. To achieve it I use solution described at MultiSelection not working in ListView (Ankesh answer). It works fine. In my application some timer is working which retrieves devices status every 10 seconds and it assign ObservableCollection as ItemsSource to my ListView and then my selected rows are deselected.
I thought that when I store selected items before reloading data to temporary variable and assign it later it will work, but I have some problems which I can't diagnose.
This is my code (reloading data block):
if (SelectedMachines != null)
{
foreach (var selectedMachine in SelectedMachines)
{
oldSelected.Add(selectedMachine.Clone()); // clone objects
}
SelectedMachines.Clear();
}
Machines = Controller.GetAutomats(); // assign data
if (SelectedMachines != null) // restore selection
{
foreach (var selectedMachine in oldSelected)
{
SelectedMachines.Add(Machines.Where(t => t.Id == selectedMachine.Id).FirstOrDefault());
// at this point SelectedMachines has same elements count as before assign
}
}
Unfortunately such code clears selection after reloading data.
Using reflector I found the following code in the System.Web.UI.WebControls.Parameter class:
internal void UpdateValue(HttpContext context, Control control)
{
object obj2 = this.ViewState["ParameterValue"];
object obj3 = this.Evaluate(context, control);
this.ViewState["ParameterValue"] = obj3;
if (((obj3 == null) && (obj2 != null)) ||
((obj3 != null) && !obj3.Equals(obj2)))
{
this.OnParameterChanged();
}
}
The line
this.OnParameterChanged();
is what triggers the ParametersChanged-event in the end, as I understand (through this._owner.CallOnParametersChanged() in OnParameterChanged).
Now my question is: what happens if EnableViewState is set to false (e.g. on the whole page)? And as an addendum: I am using ControlParameters pointing at the SelectedValue of a DropDownList.
I assume this would mean:
obj2 would either be the value that has been set earlier in the same request (i.e. UpdateValue has been called before) or null if no other value has been set yet.
As a DropDownLists SelectedValue cannot be null obj3 will never be null.
OnParametersChanged will always be invoked the first time UpdateValues is called in any request.
But if the same entries are loaded into the DropDownList during a PostBack ASP.NET retains the selection in the list across the PostBack even if ViewState is disabled (I can only guess how that works but it does...).
This comes down to the following: if ViewState is disabled and the same values are being loaded into the DropDownList on every request and the user had chosen entry X "long ago" and triggered a PostBack by other means than changing the selection in the DropDownList ASP.NET would fire a ParametersChanged-event on the ParameterCollecion (because of #3 in the list above) although in my understanding the parameter did not change its value.
Am I wrong or does this mean I cannot (should not) disable ViewState if this behaviour is causing trouble?
UPDATE (not directly related to the question)
Just to get rid of the question how the DropDownList preserves the selected value through a post back if viewstate is disabled: by its implementation of IPostBackDataHandler...
Reflector reveals (in DropDownList):
protected virtual bool LoadPostData(string postDataKey,
NameValueCollection postCollection)
{
string[] values = postCollection.GetValues(postDataKey);
this.EnsureDataBound();
if (values != null)
{
base.ValidateEvent(postDataKey, values[0]);
int selectedIndex = this.Items.FindByValueInternal(values[0], false);
if (this.SelectedIndex != selectedIndex)
{
base.SetPostDataSelection(selectedIndex);
return true;
}
}
return false;
}
So it essentially retrieves the value of the selected item in the POSTed data and if it can find an item with this key in the list of items the DropDownList contains it sets it as selected.
You are correct: you cannot disable viewstate if you want the ASP.NET web control 'changed' events and behaviors to work.
The basic mechanism they use to determine whether there has been a change is to compare the value serialized in viewstate to the equivalent posted value (if any). TextBox.TextChanged (for example) spells this out clearly in its class documentation:
A TextBox control must persist some
values between posts to the server for
this event to work correctly. Be sure
that view state is enabled for this
control.