TFS workitem field cannot be validated in Eval - c#

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();
}
}
}
}

Related

Int field in Winform does not update null values in SQL Server database using C#

In my Winforms C# application, I have fields with Int data type and they are set to accept null values in SQL Server database (allow nulls).
In the forms I have some textboxes which are bound to those int data type fields. If I don't enter anything while creating a new record, it accepts. If I enter a number in the textbox, it also accepts it, and then if I delete it, it doesn’t accept it anymore and even doesn't allow me to move to the next field.
If I set its value as null or "" through code, it simply ignores and does not even update changes which I made in other non int text fields.
I am using following method to update.
this.Validate();
this.itemsbindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.sBSDBDataSet);
What can I do for the textbox to accept null values?
I have tried following.
IDTextBox.Text = "";
IDTextBox.Text = null;
I have tried following with the help of above solutions (specially Mr. Ivan) and this is how it worked out.
To clear the int field on the form:
IDTextBox.Text = String.Empty;
Then on Designer.cs file of the form, as suggested by Mr. Ivan, I searched for 'IDtextbox.DataBindings.Add' and replaced
this.IDTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.itemsbindingSource, "PictureID", true));
with
this.IDTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.itemsbindingSource, "PictureID", true, System.Windows.Forms.DataSourceUpdateMode.OnValidation, ""));
It took me a whole day to search and finally I posted my problem here, and it got solved in 1 hour.
This seems to be one of the WF data binding bugs. I can't say what exactly is causing it, but in order to make it work one should set Binding.NullValue property to "" (empty string, the default is null).
I couldn't find a way to do that in the designer, and also it would be quite annoying to locate all text boxes needed. So I would suggest you the following quick-and-dirty approach. Create a helper method like this:
public static class ControlExtensions
{
public static void FixTextBoxBindings(this Control control)
{
if (control is TextBox)
{
foreach (Binding binding in control.DataBindings)
if (binding.NullValue == null) binding.NullValue = "";
}
foreach (Control child in control.Controls)
child.FixTextBoxBindings();
}
}
and then simply include the following in your form Load event:
this.FixTextBoxBindings();
TextBox dont accept null value.
You can check if it null and set String.Empty;
If(dbValue == null)
{
IDTextBox.Text = String.Empty;
}
else
{
// here set value to your textbox
}

silverlight, ListBox navigation to new page with object possible?

Hi all i have a listbox MainListBox where i add items to dynamically.
Now i want to navigate to DetialsPage.xaml.cs when i choose an item in the listbox.
where i can then display my info about the selected item.
private void SetListBox()
{
foreach (ToDoItem todo in itemList)
{
MainListBox.Items.Add(todo.ToDoName);
}
}
MainListBox_SelectionChanged ("Generated by visual studio 2010 silverlight for windows 7 phone)
// Handle selection changed on ListBox
private void MainListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// If selected index is -1 (no selection) do nothing
if (MainListBox.SelectedIndex == -1)
return;
// Navigate to the new page
NavigationService.Navigate(new Uri("/DetailsPage.xaml?selectedItem=" + MainListBox.SelectedIndex, UriKind.Relative));
// Reset selected index to -1 (no selection)
MainListBox.SelectedIndex = -1;
}
in DetailsPage.xaml.cs is the next method. ("Generated by visual studio 2010 silverlight for windows 7 phone)
I'm aware that the below method does not do what i try.
// When page is navigated to set data context to selected item in list
protected override void OnNavigatedTo(NavigationEventArgs e)
{
string selectedIndex = "";
if (NavigationContext.QueryString.TryGetValue("selectedItem", out selectedIndex))
{
int index = int.Parse(selectedIndex);
DataContext = App.ViewModel.Items[index];
}
}
I would like to access the selectedIndex and call my methods of my object that is in the MainListbox
so Basicly:
Mainlistbox => select item => send that item to details page => details page access the item and call methods on the item (object)
I'm sure this is a basic question tough it seems hard to find any specifics on it. i would like to add that this is my first windows phone 7 app.
There are many ways you can pass an object from page to page:
serialize and deserialize like Dennis said, but this, although feasable, is not practical, unless you want to save the object in isolated storage and retrieve it later.
Place an object in the App.cs class, which is accessible to all pages. Set your object in the master page, retrieve it from the Details page.
Code to put in App.cs: MyObject selectedObject;
Code to put in MasterPage.cs: application.selectedObject = MainListBox.selectedItem;
Code to put in DetailsPage.cs: MyObject selectedObject = application.seletedObject;
You can set the Object in the DataContext of your LayoutRoot, but i don't have the code for that on top of my head.
The answer here is simple - you cannot directly pass an object to another page. You can serialize it to JSON or XML and then deserialize it on the target page, but the serialized item will still have to be passed as a parameter.
Instead of sending the selectedindex as a query string parameter you could send the ID for the object or similar, something that uniquely can identify the object.
Then in the details page you could fetch the correct object from the same datasource that the main list box get its data from (in your case "itemList" which could come from e.g. IsolatedStorage).
If itemList is instantiated and kept only within the main page then you won't be able to fetch the item by ID from the details page. So in that case you'd need to move the itemList to some static or app level storage.
HTH

Silverlight dataform currentitem issue

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.

Correct way to implement web part personalisation for listboxes

Trying to work out this whole web part personalisation, and trying to implement it for a list box.
Well the end result will be two list boxes, with interchangeable values (ie, a value will only exist in one of the listboxes)
But I can't maintain the datasource for it. So maybe I'm going about it wrong?
This is what I have for a test H2 tag on the page
[Personalizable(PersonalizationScope.User)]
public string LabelText {
get { return h2Test.InnerText; }
set { h2Test.InnerText = value; }
}
And it works fine, if I have a textbox and use it to change the value of LabelText, then when I close the browser it automagically persists the change.
So I thought, ok, then maybe the same will work with a list box
[Personalizable(PersonalizationScope.User)]
public DomainList Domains {
get { return (DomainList)lstBxDomains.DataSource; }
set {
lstBxDomains.DataSource = value;
lstBxDomains.DataBind();
}
}
Where DomainList is just a class which extends List, and Domain is just a three field class, int, string, string.
But it doesn't, so is this too complicated for the webpart personalisation automagican, or have i just implement it wrongly (Which is more than likely)
This is my event handler to remove the items from the list:
protected void btnRemDomain_Click(object sender, EventArgs e) {
if (IsPostBack && lstBxDomains.SelectedIndex > -1) {
for (int i = 0; i < lstBxDomains.Items.Count; i++) {
if (lstBxDomains.Items[i].Selected) {
Domains.Remove(Domains.Find(d => d.ID.ToString() == lstBxDomains.Items[i].Value));
}
}
Domains = Domains;
}
}
The Domains=Domains; line is in there to see if explicitly setting the value made a difference (as Removing doesn't acutally reset the value of the field), but it doesn't. I've also tried creating a new local DomainList setting it to the global one, and then doing the remove/find on it, and then setting the local one to the global. But not working either.
I have managed to resolve this by using WebPart.SetPersonalizationDirty(this); in the set accessor of Domains, but would someone mind confirming if this is an appropriate way to do it?

Why DataBinding doesn't work on second time around?

The error I got when I change the datasource of BindingSource
"databinding cannot find a row that is suitable for all bindings row that is suitable for all bindings"
this.RemoveAllBindings(); // My work-around for the meantime
bdsOrder.DataSource = _ds.Tables["orders"]; // errors here on second time around(first time is blank datatable, second time is when i open existing record, then it errors), dataset comes from Remoting
bdsOrderDetail.DataSource = _ds.Tables["order_detail"];
bdsPhoto.DataSource = _ds.Tables["order_photo"];
bdnPhoto.BindingSource = bdsPhoto;
My Helper extension method work-around on perplexing "databinding cannot find a row..." error.
namespace MycComponentExtension
{
public static class Helper
{
public static void RemoveAllBindings(this Form form)
{
RemoveAllBindings((Control)form);
}
private static void RemoveAllBindings(this Control root)
{
foreach (Control c in root.Controls)
{
if (c.Controls.Count > 0) RemoveAllBindings(c);
root.DataBindings.Clear();
}
}
What's the meaning of "DataBinding cannot find a row..." error, if at all possible, can I eliminate my work-around on it?
I have seen this error when no DataGridView is involved, but my data source was being updated from another thread (naughty!) and my binding had FormattingEnabled=false. Changing both of these seemed to fix the problem.

Categories

Resources