Silverlight 4 dataform add new item - silverlight-4.0

I'm using a Silverlight 4 dataform and attempting to use the inbuilt add button to create a new item in my collection. It works fine except that I have a number of properties that need to be set behind the scenes. I've tried hooking into the likely looking events such as AddingNewItem but the new item is readonly at that point and I can't set the properties.
Is there a trick to add new items using the Silverlight 4 dataform?

Finally stumbled on the way to do it after much searching and trial and error.
The rather counter-intuitive place to set the properties on a newly created dataform item is in the EditEnding event handler. The dataform Mode property is readonly in the AddingNewItem handler but is equal to AddNew in the EditEnding handler.
My EditEnding handler code is along the lines of:
private void EditEnding(object sender, DataFormEditEndingEventArgs e)
{
if (myDataForm.Mode == DataFormMode.AddNew)
{
MyItem item = myDataForm.CurrentItem as MyItem;
item.ID = Guid.NewGuid().ToString();
}
}

Related

XAML forms have second picker sorted based on selection in first picker

I have 2 dropdowns (pickers) on a XAML form. The first is an ObservabelCollection of Territories. The second is an ObservableCollection of type Tracks. When the form loads my ViewModel loads both collections and each collection is bound to a picker. I want to filter and display only those tracks that are associated with the selected territory in the second picker.
FYI-the second picker is disabled until a selection is made in the first. Actually I don't require that the second picker's data source be set as the form loads, unless the solution requires it. The selection in the first picker will be the key to filter the data for the second.
I have tried to handle the filtering in the Territory picker's SelectedIndexChanged event but my ObservableCollection 'tracks' is not exposed here.
private void territoryPicker_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
string territory = picker.SelectedItem.ToString();
Tracks _track = tracks.Where(X => X.Territory = territory);<<<==== Does not work
trackPicker.ItemsSource = _track.Track;<<<==== Does not work
trackPicker.IsEnabled = true;
}
I've also tried to not build the Tracks OC until after the Territory is selected like this:
private void territoryPicker_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
string territory = picker.SelectedItem.ToString();
TrackViewModel vm = new TrackViewModel();
var _tracks = (Tracks)vm.Tracks; <<<<<==== This does not work
trackPicker.IsEnabled = true;
}
The ViewModel runs and the tracks are loaded via the API but when it returns here Tracks is empty.
I'm open to a reasonable solution (not 3rd party controls/packages) that will accomplish this task . Thanks
I figured it out by stumbling over the answer while researching another issue. I have been referencing my viewmodel in the {content].xaml page like this.
<ContentPage.BindingContext>
<vm:TrackViewModel />
</ContentPage.BindingContext>
When doing so the resources of that vm were not available in the code behind. But when I reference the VM in the page constructor Like this:
public partial class RequestmyTracks : ContentPage
{
TrackViewModel trackviewmodel = new TrackViewModel();
And then bind it here:
public RequestmyTracks()
{
InitializeComponent();
BindingContext = trackviewmodel;
}
The trackviewmodel is accessible in the SelectedIndexChanged event and everything else was really straight forward, Which looks like this:
private void territoryPicker_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
string territory = picker.SelectedItem.ToString();
ObservableCollection<Tracks> dah = (ObservableCollection<Tracks>)trackviewmodel.Tracks;
List<string> trackNames = new List<string>();
foreach (var track in dah)
{
if (track.Territory == territory)
trackNames.Add(track.Track);
}
trackPicker.ItemsSource = trackNames;
if(trackNames.Count ==1)
trackPicker.SelectedIndex = 0;
trackPicker.IsEnabled = true;
}
Thanks for the help

notifyDatasetchanged not working for ArrayAdapter

I am trying to implement 2 AutoCompleteTextView. First one holds the value, on click of one of them will populate the data in second AutoCompleteTextView, all works and data gets loaded correctly however when I try to call notifyDataSetChanged on the second adapter which populates the second field that does not get changed.
I also wrote that piece of code inside a Handler too, however that does not seems to work either.
branchAdapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,branchNames);
et7.setAdapter(branchAdapter);//et7 is the AutoCompleteTextView //branchname is the ArrayList
in some method I clean up the ArrayList and add the new data into it and then call notifyDataSetChanged like below
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
branchAdapter.notifyDataSetChanged();
}
});
Which is not updating the list. What should be the correct way here to update data?
#Saty, I guess i am a little late to the party. I am answering, keeping in mind that, it may help somebody in future.
Cleanup the adapter as well using branchAdapter.clear() method. Then add new items to the adapter using branchAdapter.addAll(String... items) method. Now, call branchAdapter.notifyDataSetChanged() method. This will work.
Try resetting listview instead.
ListView lv = (ListView)findViewById(R.id.lv);
ArrayAdapter adapter = new ArrayAdapter(/*with all parameters*/);
lv.setAdapter(adapter);

Invoking Method of Presenter on Activation

I'm using Smart Client Software Factory 2008. In the module controller, I have code that creates a new child controller only if it hasn't been created, by doing something like the following:
Dim key = "Item-" + item.ID.ToString()
Dim childWorkItem = Me.WorkItem.WorkItems.Get(Of ControlledWorkItem(Of ItemWorkItemController))(key)
If childWorkItem Is Nothing Then
childWorkItem = Me.WorkItem.WorkItems.AddNew(Of ControlledWorkItem(Of ItemWorkItemController))(key)
Else
childWorkItem.Activate()
End If
Multiple items reuse the same key, so when that action is triggered, it shows the tab instead of creating a new instance of it. This works great.
However, there is one drawback. Once activated, I need to run a check within that item's presenter. So I need to call a method on the presenter. Is there a way to invoka a method on the presenter, or is there an event that runs on the view when the work item is activated? I'm not sure how to make that happen?
Thanks.
If you are using a Smart Part as your View you should be able to accomplish this using the IWorkspace.SmartPartActivated event.
This is how I have it setup in my project. I apologize, my code is all in C# but you should be able to apply it in VB relatively easily.
The WorkItemController class has the Activate method setup like this
ISmartPartView _smartPartView
public void Activate()
{
IWorkspace contentWorkspace = this.WorkItem.Workspaces[WorkspaceNames.ShellContentWorkspace];
contentWorkspace.Activate(_smartPartView);
WorkItem.Activate();
}
In the ISmartPartView Presenter class you should be able to create a handler for the SmartPartActivated event like this:
IWorkspace contentWorkspace = this.WorkItem.Workspaces[WorkspaceNames.ShellContentWorkspace];
contentWorkspace.SmartPartActivated += workSpaceSmartPart_ActivatedHandler;
In the workSpaceSmartPart_ActivatedHandler event handler, you can check the SmartPart being activated and if its your ISmartPartView class you can run the desired code.

How to add a new entity to a domain context and immediately see it in data bound controls before SubmitChanges?

I've got a Silverlight 4 RIA Services (SP1) app using Entity Frameworks 4 CTP5. I can databind a grid or listbox to the IEnumerable loaded by the domain context and it shows data from the server. Great.
Now I want to create a new instance of MyEntity and add it to the client-side data so that the user can see the newly added entity. MyEntity is a true entity descendant, not a POCO.
The only Add method I can find is domainContext.EntityContainer.GetEntitySet<MyEntity>().Add(newobj)
This does add the new entity to the domain context, and the domainContext.HasChanges does become true, but the new entity doesn't show up in the databound controls.
How do I get the new entity to show up in the databound controls prior to SubmitChanges?
(Probably related to this SO question from years ago that never got an answer)
Here's the server side declarations of the domain service, per requests:
[EnableClientAccess()]
public class MyDomainService : LinqToEntitiesDomainService<MyObjectContext>
{
protected override MyObjectContext CreateObjectContext()
{
return new MyObjectContext();
}
public IQueryable<MyEntity> GetMyEntities()
{
return this.ObjectContext.MyEntities;
}
public void InsertMyEntity(MyEntity MyEntity)
{
// ...
}
public void UpdateMyEntity(MyEntity currentMyEntity)
{
// ...
}
public void DeleteMyEntity(MyEntity MyEntity)
{
// ...
}
}
I've figured this out with a combination of my own trial and error and hints provided by some of the other responses to this question.
The key point I was missing was that it's not enough for the ViewModel to keep track of the DomainContext and hand out query results to the View for databinding. The ViewModel also has to capture and retain the query results if you want entity adds and deletes performed by the ViewModel to appear in the UI before DomainContext.SubmitChanges(). The ViewModel has to apply those adds to the collection view of the query results.
The ViewModel collection property for View databinding. In this case I'm using the Telerik QueryableDomainServiceCollectionView, but other collection views can be used:
public IEnumerable<MyEntity> MyEntities
{
get
{
if (this.view == null)
{
DomainContextNeeded();
}
return this.view;
}
}
private void DomainContextNeeded()
{
this.context = new MyDomainContext();
var q = context.GetMyEntitiesQuery();
this.view = new Telerik.Windows.Data.QueryableDomainServiceCollectionView<MyEntity>(context, q);
this.view.Load();
}
The ViewModel function that adds a new entity for the UI to display:
public void AddNewMyEntity(object selectedNode)
{
var ent = new MyEntity() { DisplayName = "New Entity" };
if (selectedNode == null)
{
this.view.AddNew(ent);
}
else if (selectedNode is MyEntity)
{
((MyEntity)selectedNode).Children.Add(ent);
}
}
Other responses mentioned ObservableCollection. The query results and the collection view may not return instances of ObservableCollection. They could be just IEnumerables. What is critical is that they implement INotifyCollectionChanged and IEditableCollectionView.
Thanks to those who contributed responses. I've +1'd each response that was helpful, but since none directly solved my problem I couldn't justify marking any as the definitive answer.
Your domainContext will have a property domainContext.MyEntities. Does it not show up in there when you add it?
Bind to that collection or watch that collection for changes.
domainContext.MyEntities.PropertyChanged += MyEventHandler;
I assume you bind your control to the IEnumerable which is provided by LoadOperation<TEntity>.Entities. In that case your binding source is not the DomainContext.GetEntitySet<MyEntity>().
DomainContext.GetEntitySet<MyEntity>() holds all your currently tracked instances of MyEntity, including the one you add with .Add().
LoadOperation<TEntity>.Entities only contains the instances of MyEntity that were actually loaded by your last LoadOperation/Query.
You have two options: Either add the new entity to the ItemsSource-collection for your control (I recommend that) or rebuild the collection with the contents of DomainContext.GetEntitySet<MyEntity>(). That may contain other elements that you have not cleared out before, though.

Adding content to silver light controls from database using wcf ria services

I am trying to retrieve strings from the database and add it as content to the controls on my page before it loads(somewhat like a custom localization). I retrieve my strings from the database uing ria services as follows:
**
Web.DomainService1 context = new Web.DomainService1();
LoadOperation<Web.LocalizationTab>LoadOp=context.Load(context.GetLocalizationTabsQuery(currentCulture, moduleName));
Dictionary<string, string> localizationDictonary = new Dictionary<string, string>();
List<Web.LocalizationTab> localList = new List<Web.LocalizationTab>();
LoadOp.Completed += (s, e) =>
{
localList = LoadOp.Entities.ToList<Web.LocalizationTab>();
//System.Windows.MessageBox.Show(localList.Count.ToString());
foreach (Web.LocalizationTab item in localList)
{
// var control = this.FindName(item.Control_ID.ToString());
if (!localizationDictonary.ContainsKey(item.Control_ID))
{
localizationDictonary.Add(item.Control_ID, item.Control_Text);
}
}
};**
This piece of code is in a separate class called utilities.cs.
now in my Mainpage.xaml.cs i need to get this dictionary with values and then set the controls with the strings from the dictionary.
my problem is that when i do the following in the constructor of Mainpage.xaml.cs:
utilities.getDict(ModuleName);
button1.Content = localizationDictonary["button1"].ToString();
i get an exception as the dictionary doesnt contain values at that point of time.. The load completed event of getting data from the database gets fired only after my constructor is exited. now how do i go about setting my controls automatically in this particular scenario??
Try loading your dictionary in the Silverlight Application class StartUp event. This should ensure that your Dictionary is loaded (and could be placed in the Application Resources for retrieval elsewhere in your application).
You'll need to wait for the GetLocalizationTabsQuery to complete before instantiating your MainPage. In your App.xaml.cs file, you can start the query, add a query completed handler, and only create the MainPage when the query completed handler gets called.