Is it possible to edit data in a SilverLight Child window when using RIA Services and Silverlight 4? It sounds like a simple enough question, but I have not been able to get any combination of scenarios to work.
Simply put, I am viewing data in a grid that was populated through a DomainDataSource. Instead of editing the data on the same screen (this is the pattern that ALL of the Microsoft samples seem to use), I want to open a child window, edit the data and return. Surely this is a common design pattern.
If anyone knows of a sample out there that uses this pattern, a link would be much appreciated.
Thanks,
Rick Arthur
This is a Microsoft sample that uses a ChildWindow. It uses RIA services, but not MVVM.
It doesn't fix a problem I'm having where entities get attached to my context before I want them to be, but does what you're looking for other than that.
Here's the relevant code to save you downloading the zip:
private void addNewEmployee_Click(object sender, RoutedEventArgs e)
{
EmployeeRegistrationWindow addEmp = new EmployeeRegistrationWindow();
addEmp.Closed += new EventHandler(addEmp_Closed);
addEmp.Show();
}
public partial class EmployeeRegistrationWindow : ChildWindow
{
public EmployeeRegistrationWindow()
{
InitializeComponent();
NewEmployee = new Employee();
addEmployeeDataForm.CurrentItem = NewEmployee;
addEmployeeDataForm.BeginEdit();
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
addEmployeeDataForm.CommitEdit();
this.DialogResult = true;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
NewEmployee = null;
addEmployeeDataForm.CancelEdit();
this.DialogResult = false;
}
public Employee NewEmployee { get; set; }
}
The MVVM light Toolkit found here has messeging between viewmodels for more information check above site. Please write if u need an example.
Related
I'm having difficulty finding how to register a RoutedEventHandler in UWP. I'm attempting to code a template control that has event properties similar to ContentDialog's:
PrimaryButtonClick="ClickEvent"
Where ClickEvent is defined in the cs file. I'm only just getting the hang of templates, but I believe I want to do something that looks like this:
<Button Content="{TemplateBinding PrimaryButtonText}" Click="{TemplateBinding PrimaryButtonClick}"/>
Currently, all I can find is references to WPF versions of this type of code:
public static readonly RoutedEvent ValueChangedEvent =
EventManager.RegisterRoutedEvent("ValueChanged",
RoutingStrategy.Direct, typeof(RoutedPropertyChangedEventHandler<double>),
typeof(NumericBox));
public event RoutedPropertyChangedEventHandler<double> ValueChanged
{
add { AddHandler(ValueChangedEvent, value); }
remove { RemoveHandler(ValueChangedEvent, value); }
}
private void OnValueChanged(double oldValue, double newValue)
{
RoutedPropertyChangedEventArgs<double> args =
new RoutedPropertyChangedEventArgs<double>(oldValue, newValue);
args.RoutedEvent = NumericBox.ValueChangedEvent;
RaiseEvent(args);
}
But of course the types have changed. Can someone point me in the right direction?
Unfortunately, the concept of RoutedEvent (bubbling, tunneling) is not available in UWP currently. You can just create a classic event however instead:
public event EventHandler PrimaryButtonClick;
protected void InnerButton_Click(object sender, EventArgs e)
{
PrimaryButtonClick?.Invoke( sender, e );
}
Bubbling of events is possible for some predefined events, but it is not yet possible to allow bubbling for custom events in current version of UWP.
Here is how it works:
Filter web part sends row of data to all other webparts on the page.
It's control is rendered at load time, rendering the control selects which row is sent back to the other webparts on the page.
This causes the issue on the first page load where the other webparts will request the row from provider before it has finished loading and therefore has no information to provide yet.
The only solution (which is really ugly, slow and horrible) is to run all of the code that would be run in the control class the webpart uses in the webpart's constructor and use it to predict what values the control will have on the first run. This also leads to a whole bunch of issues with deploying that I really would rather avoid.
Here's the webpart code:
public class FilterProjectHeader : WebPart, IWebPartRow
{
// Visual Studio might automatically update this path when you change the Visual Web Part project item.
private const string _ascxPath = #"[link goes here]";
public DataRowView data;
public DataTable table;
private FilterProjectHeaderUserControl control;
public FilterProjectHeader()
{
//Code I want to avoid using:
//var web = SPContext.Current.Web;
//table = web.Lists["foo"].Items.GetDataTable();
//data = foo();
}
protected override void CreateChildControls()
{
control = Page.LoadControl(_ascxPath) as FilterProjectHeaderUserControl;
control.provider = this;
Controls.Add(control);
}
public PropertyDescriptorCollection Schema
{
get
{
return TypeDescriptor.GetProperties(table.DefaultView[0]);
}
}
[ConnectionProvider("Row")]
public IWebPartRow GetConnectionInterface()
{
return this;
}
public void GetRowData(RowCallback callback)
{
callback(data);
}
}
And for the control:
public partial class FilterProjectHeaderUserControl : UserControl
{
public FilterProjectHeader provider { get; set; }
private String _selectedValue;
//Both OnLoad and OnInit have the same result.
protected override void OnInit(EventArgs e)
{
//This is what gets run the first time:
if (!IsPostBack)
{
//Code here finds data then sends it back to webpart like this:
//All of the code in this method definitely does run; I have stepped
//through it and it works but it seems to happen too late to have any
//effect.
provider.data = item;
provider.table = profilesTable;
}
}
protected void filterDropDown_SelectedIndexChanged(object sender, EventArgs e)
{
//Post back method code exempted... it works.
provider.data = item;
provider.table = profilesTable;
}
So after a lot of time working with this, I found the issue is actually with what Microsoft recommends to do as best practice (they say to always use CreateChildControls to load controls onto the page).
CreateChildControls runs AFTER OnLoad when it is the first time a page is loading, but runs BEFORE OnLoad on a repost.
This is why it works on reposts, but not on first page load.
Switching CreateChildControls to OnInit solves the problem, because OnInit will always run before OnLoad.
I was wondering how to wire up Castle Windsor in WebForms.
I'm assuming that the second line wires up the controllers in MVC:
// Initialize Windsor
IWindsorContainer container = new WindsorContainer().Install(FromAssembly.This());
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container.Kernel));
How do I then wire up WebForms in ASP.NET?
I had a project which I have modified into an identical WebForms setup. Everything works up until the point where I want Castle Windsor to inject ISession into the ASPX page. It simply doesn't and I am under the assumption that the second line of code, above, is what does it for MVC controllers.
I have this in my nHibernate installer, in teh same place on both projects:
container.Register(Component.For<ISession>()
.LifeStyle.PerWebRequest
.UsingFactoryMethod(kernel => kernel.Resolve<ISessionFactory>().OpenSession()));
I had originally assumed this would do it but it is not the case.
I have been stuck on this for days and with very little official documentation on this I am close to ripping my hair out, what's left of it.
I do know the ASP.NET WebForms are not specifically designed to work with dependancy injection but Ninject have done it, albeit with a little hacking, if I can confirm that Castle Windsor is not compatible and/or will no longer support WebForms I will move to something else.
I managed to stuff Castle Windsor in to WebForms using the code here How to use Castle Windsor with ASP.Net web forms? It uses an an attribute to mark where a dependency should be injected in the a WebFrom.
I then used an MVP pattern. Each WebForm had a presenter
public partial class TestPage : UserControl, IShowTestPage
{
[Inject]
public TestPagePresenter Presenter { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack) return;
this.Presenter.OnViewInitialized();
}
public string TestMessage
{
get { return litTestMessage.Text; }
set { litTestMessage.Text = value; }
}
}
As the Presenter is resolved form the container, it is then back to normal for wiring up the dependencies
public interface IShowTestPage {
string TestMessage { get; set;}
}
public class TestPagePresenter {
private ISession session;
public TestPagePresenter(ISession session) {
this.session = session;
}
private IShowTestPage view;
public IShowTestPage { set { view = value; } }
public void OnViewInitialized {
TestMessage = session.Query("some database query");
}
}
My solution was based on a great article by Billy McCafferty
Although there are many examples of Silverlight projects using MEF (Managed Extensibility Framework), since the System.ComponentModel.Composition.Packaging.Toolkit package was removed in the version that is shipped inside Silverlight 4, these projects are away from helping to run some basic MEF example.
Some tutorials using the newer API will be very beneficial.
Thanks.
Although I can't point you in the direction of a concrete example, it's quite trivial to start composing parts of your Silverlight 4 application. Given the example:
public partial class MainPage : UserControl, IContext
{
[ImportMany]
public IEnumerable<IPlugin> Plugins { get; set; }
public MainPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
Plugins.First().Run(this);
}
public void ShowMessage(string message)
{
textBox1.Text = message;
}
}
public interface IContext
{
void ShowMessage(string message);
}
public interface IPlugin
{
void Run(IContext context);
}
[Export(typeof(IPlugin))]
public class SamplePlugin : IPlugin
{
public void Run(IContext context)
{
context.ShowMessage("Hello World");
}
}
The CompositionInitializer type provides SatisfyImports methods which action a default CompositionContainer which is plugged into a catalog that reads parts from your deployed XAP files. If you want more fine grained control over how the catalog is created, you can always create your own CompositionContainer.
Are there any particular aspects of MEF with Silverlight you are looking for advice on?
I wrote a blog post how you can implement MEF into you Silverlight applictaion see
http://www.arrangeactassert.com/solid-design-principles-using-mef-in-silverlight-and-wpf/
I think this is what you are after.
I've got a RIA silverlight 4 app with a complex data type as a model. As a familiar example let's call it aspnet_User which has a member object called aspnet_Membership; aspnet_User has a member called "UserName" and aspnet_Membership has a member called "Email". Now using the aspnet_User as a datacontext I want to bind to any changes in aspnet_User or an attached aspnet_Membership - i.e. I want to show if an aspnet_User is 'dirty'. The dirty flag should show if I change either aspnet_User.UserName or aspnet_Membership.Email. Now previously I have implemented a Converter and bound to the EntityState on an object, and this is fine for showing whether simple properties are dirty but EntityState is not altered when aspects of aspnet_Membership member are edited.
I have tried to implement a property called BubbledEntityState which reflects a modified EntityState on either aspnet_User or aspnet_membership. It is defined in a partial class in the Silverlight project. This needs to react to EntityState PropertyChanged events on aspnet_User or it's member aspnet_Membership. So I've tried to handle these events in the partial OnCreated method. Strangely however this isn't getting called at all. Here is the method:
public partial class aspnet_User
{
partial void OnCreated()
{
this.aspnet_Membership.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(aspnet_Membership_PropertyChanged);
this.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(aspnet_User_PropertyChanged);
}
...
}
I'm presuming aspnet_User objects are constructed on the server and are not 'reconstructed' when they are reconstituted on the client after RIA has done it's WCF call. This strikes me as peculiar. Am I doing something cranky? Anyone got a better way of dealing with this?
OK I've got this working. It still seems a bit convoluted, but rather than using the OnCreated partial method I've overloaded the OnLoaded method:
protected override void OnLoaded(bool isInitialLoad)
{
base.OnLoaded(isInitialLoad);
this.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(aspnet_User_PropertyChanged);
}
partial void OnCreated()
{
}
void aspnet_User_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "aspnet_Membership")
{
if (this.aspnet_Membership != null)
{
this.aspnet_Membership.PropertyChanged+=new System.ComponentModel.PropertyChangedEventHandler(aspnet_Membership_PropertyChanged);
}
}
if (e.PropertyName == "EntityState")
this.OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs("BubbledEntityState"));
}
void aspnet_Membership_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "EntityState")
this.OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs("BubbledEntityState"));
}
public EntityState BubbledEntityState
{
get
{
if (this.EntityState== System.Windows.Ria.EntityState.Unmodified)
{
if (this.aspnet_Membership==null)
return System.Windows.Ria.EntityState.Unmodified;
if (this.aspnet_Membership.EntityState== System.Windows.Ria.EntityState.Modified)
return System.Windows.Ria.EntityState.Modified;
return System.Windows.Ria.EntityState.Unmodified;
}
return this.EntityState;
}
}