I am currently trying to figure out a binding solution in Silverlight 4.
I have an observable collection of items. I want to bind this to a ComboBox but only display the items that match a certain condition. For example group == "Test Group." I have tried quite a few ways to make this work but haven't had any success.
In the past I have used LINQ in an exposed property on the VM e.g:
/// <summary>
/// Get filtered results(by location)
/// </summary>
public ObservableCollection<SearchResultData> FilteredResults {
get
{
return new ObservableCollection<SearchResultData>(Results.Where(p => p.LocationId == CurrentLocation.Id));
}
}
Using this approach you will need to provide a notification when the underlying collection in the LINQ changes e.g:
public ObservableCollection<SearchResultData> Results
{
get { return _results; }
set
{
_results = value;
NotifyOfPropertyChange(() => Results);
NotifyOfPropertyChange(() => FilteredResults);
}
}
Related
MVVMCross ListView - How to display a list of items in a listview grouped by a status? For exampled activate or deactivated
I have added two listview to the layout and set the datasource to have two lists (activatedItems and deactivatedItems => both of them derived from ListOfItems. ) using the xaml data binding with now code behind. But had a problem in the data not updated when there is a change to the underlying list (ListOfItems).
To resolve this, I have to re create the UI by setting the content view whenever there a change to the data set.
This is not an elegant solution and I would like to have one listview with sections "Activated" and "Deactivated". Then on touching the Activated item should get added to the Deactivated list and the UI should reflect the same.
Since you have a LoginItemModel with a Title property (let's assume it's a string property), I would recommend you to extract this to an ILoginItemModel interface and also add a bool IsHeader property. This way:
public interface ILoginItemModel {
public bool IsHeader { get; }
public LoginSection ItemGroup { get; }
public string Title { get; }
}
Make your LoginItemModel extend this ILoginItemModel interface and make IsHeader always return false.
public bool IsHeader => false;
Write a second class extending this same interface, let's call it LoginItemHeaderModel. This class will just have these three properties:
public class LoginItemHeaderModel : ILoginItemModel {
public bool IsHeader => true;
LoginSection _itemGroup;
public LoginSection ItemGroup => _itemGroup;
string _title;
public string Title => _title;
public LoginItemHeaderModel(LoginSection itemGroup, string title) {
_itemGroup = itemGroup;
_title = title;
}
}
Now we have two models that fits into a single IList<ILoginItemModel>.
Back to your view model, you can declare a fourth list property and put it all together along with your new headers:
public List<ILoginItemModel> SectionedLoginItems {
get {
var values = Enum.GetValues(typeof(LoginSection)).Cast<LoginSection>();
List<ILoginItemModel> list = new List<ILoginItemModel>();
foreach (LoginSection loginSection : values) {
list.Add(new LoginItemHeaderModel(loginSection, loginSection.ToString()));
list.AddRange(LoginItems.Where(l => l.ItemGroup == loginSection));
}
return list;
}
}
Now you have your single sorted and with section headers list.
You should now write a new layout for those header items (aren't you going to make them look like the common items, right?) and, in your custom MvxAdapter, inside the GetBindableView method, check whether the object source (which will be an ILoginItemModel object) is a header item or not.
Whenever you make a change to ActiveLoginItems or DeactivatedLoginItems, make a call to RaisePropertyChanged in your ViewModel i.e.
RaisePropertyChanged(() => ActiveLoginItems);
or
RaisePropertyChanged(() => DeactivatedLoginItems);
That should make the MvxListView update with the changes.
I have a Job model that contains a number of properties, and a set of linked entities called Quotes:
public class Job
{
....
public virtual ICollection<Quote> Quotes { get; set; }
}
In my Job class I have the following calculated property:
public decimal QuotesAwarded
{
get
{
if (Quotes == null || !Quotes.Any())
{
return 0;
}
var totalUnapprovedQuotes = Quotes.Where(x => x.Status != "Approved");
return 1 - (totalUnapprovedQuotes.Count() / Quotes.Count());
}
set
{
}
}
I have 2 questions:
When I debug this property, Quotes is null (even though there are attached quotes to this entity). I thought that using virtual means that this shouldn't occur? How can I ensure that whenever the model is constructed, the related Quote entities are attached?
The reason I'm doing this is that the property value is stored in the database, so it reduces compute time as it's pre-calculated, is this correct?
Follow up:
In most cases I'm not using Include<Quotes> when retrieving the job object. I'm using Include only when I need the QuotesAwarded value.
However if I don't use Include (say db.jobs.find(id)), and Quotes is null, and the QuotesAwarded value will be 0. So this will get saved to the database when I save the job object, I've really confused myself here.
For your first question, the virtual keyword is used as an indication to Entity Framework to lazily load this. However, it appears that you have disabled lazy loading so you always need to .Include(...) it. As your property is reliant on the quotes being loaded, it will always return 0.
What you are doing is almost right, you just need to let Entity Framework know that your property is a computed column. To do this, you just need to annotate it with an attribute:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public string QuotesAwarded
{
get
{
if (Quotes == null || !Quotes.Any())
{
return 0;
}
var totalUnapprovedQuotes = Quotes.Where(x => x.Status != "Approved");
return 1 - (totalUnapprovedQuotes.Count() / Quotes.Count());
}
private set
{
//Make this private so there's no temptation to set it
}
}
I've got a method in my controller that returns a List<TreeViewItemModel>() that I'm populating with the correct hierarchy. This seems to serialize correctly, but when I load the Treeview, I don't have any of the hierarchy, just the first level of nodes.
Example:
Each of the above Curricula has 2/3 scenarios underneath that I've verified are getting added as items to the base object when going from curriculum => TreeViewItemModel
Controller:
public JsonResult GetAvailableCurricula(string LocationId)
{
LocationId = "1";
if(LocationId != string.Empty)
{
var results = Logic.GetFilteredCurriculum().Select(c => CurriculumToTreeView(c));
return Json(results, JsonRequestBehavior.AllowGet);
}
else
{
return Json(new List<TreeViewItemModel>(),JsonRequestBehavior.AllowGet);
}
}
private TreeViewItemModel CurriculumToTreeView(CurriculumModel c)
{
var tree = new TreeViewItemModel()
{
Id = c.CurriculumId.ToString(),
Text = c.CurriculumName,
HasChildren = c.Scenarios.Any()
};
if (tree.HasChildren)
{
tree.Items = c.Scenarios.Select(scenario =>
new TreeViewItemModel()
{
Text = scenario.Name,
}
).ToList();
}
return tree;
}
View:
#(Html.Kendo().TreeView()
.Name("AvailableCurricula")
.DataTextField("Text")
.DataSource(source => source
.Read(read => read
.Action("GetAvailableCurricula", "TraineeAssignments")
.Data("filterAvailableCurricula")
)
)
Is there some extra step I need to take to bind the child objects AND the parent, instead of just one level at a time? I have a fairly small set of data that I don't need to reload all that often, so I would was hoping to avoid loading each level individually/on-demand.
In case it's helpful, here's the raw JSON I'm sending from the controller for one of my curricula:
{"Enabled":true,"Expanded":false,"Encoded":true,"Selected":false,"Text":"Operator B","SpriteCssClass":null,"Id":"1","Url":null,"ImageUrl":null,"HasChildren":true,"Checked":false,"Items":[{"Enabled":true,"Expanded":false,"Encoded":true,"Selected":false,"Text":"test 2","SpriteCssClass":null,"Id":null,"Url":null,"ImageUrl":null,"HasChildren":false,"Checked":false,"Items":[],"HtmlAttributes":{},"ImageHtmlAttributes":{},"LinkHtmlAttributes":{}},{"Enabled":true,"Expanded":false,"Encoded":true,"Selected":false,"Text":"Scenario II","SpriteCssClass":null,"Id":null,"Url":null,"ImageUrl":null,"HasChildren":false,"Checked":false,"Items":[],"HtmlAttributes":{},"ImageHtmlAttributes":{},"LinkHtmlAttributes":{}}],"HtmlAttributes":{},"ImageHtmlAttributes":{},"LinkHtmlAttributes":{}}
I believe that the remote data option for the Treeview uses ajax to load the child data, either on demand or at initial load - controlled by the LoadOnDemand option.
The remote data examples in the kendo docs behave that way. That is how I implemented it on a previous project. The full code example includes a treeview as well as a grid.
Is it possible to get such XML, using TFS API or other tools?
This XML contains information about the fields that must be filled in translation work item to another status.
Screen here http://sqlrefactorstudio.com/content/png/TFS%20Work%20item%20required%20fields.png
Using the TFS API in the simple example below will write out the required fields for a given work item.
/// <summary>
/// Writes out the required fields for a work item.
/// </summary>
/// <param name="workItemId">The ID of a work item.</param>
private static void _GetRequiredFieldsForWorkItem(int workItemId)
{
using (TeamProjectPicker tpp = new TeamProjectPicker(TeamProjectPickerMode.SingleProject, false, new UICredentialsProvider()))
{
if (tpp.ShowDialog() == DialogResult.OK)
{
TfsTeamProjectCollection projectCollection = tpp.SelectedTeamProjectCollection;
WorkItemStore store = projectCollection.GetService<WorkItemStore>();
Console.WriteLine("Required Work Item Fields");
Console.WriteLine("-------------------------------");
WorkItem item = store.GetWorkItem(workItemId);
foreach (Field field in item.Fields)
{
if (field.IsRequired)
{
Console.WriteLine(field.ReferenceName);
}
}
}
}
}
I'm working on TFS API 2010.
I would like to get the available option list of a field to create a Combobox control. such as:
Priority --> [1,2,3,4]
Severity-->['4-low','3-medium','2-height','1-Critical']
You will need to export the WorkItemType Definition from TFS, then find the field in the xml and use the values from there. Below is a snippet of code that I used to get a list of transitions, if you think that the options might be in a Global List then you'll set the flag in the export method to true.
public List<Transition> GetTransistions(WorkItemType workItemType)
{
List<Transition> currentTransistions;
// See if this WorkItemType has already had it's transistions figured out.
this._allTransistions.TryGetValue(workItemType, out currentTransistions);
if (currentTransistions != null)
{
return currentTransistions;
}
// Get this worktype type as xml
XmlDocument workItemTypeXml = workItemType.Export(false);
// Create a dictionary to allow us to look up the "to" state using a "from" state.
var newTransitions = new List<Transition>();
// get the transitions node.
XmlNodeList transitionsList = workItemTypeXml.GetElementsByTagName("TRANSITIONS");
// As there is only one transitions item we can just get the first
XmlNode transitions = transitionsList[0];
// Iterate all the transitions
foreach (XmlNode transition in transitions)
{
// save off the transition
newTransitions.Add(new Transition { From = transition.Attributes["from"].Value, To = transition.Attributes["to"].Value });
}
// Save off this transition so we don't do it again if it is needed.
this._allTransistions.Add(workItemType, newTransitions);
return newTransitions;
}
Transition is a small class I have as below.
public class Transition
{
#region Public Properties
public string From { get; set; }
public string To { get; set; }
#endregion
}