Silverlight, connecting service.cs and XAML.cs for database - silverlight

I've found a sample showing how to connect to SQL server (a local MDF), but it uses databinding, how can I use SQL in the normal way (insert, select, update, delete..., sqldatareader, without binding), I think all SQL staff should be performed in service.cs, so how can I use SQL from my XAML.cs? here is the service code:
and here service.cs:
public class ServiceCustomer : IServiceCustomer
{
public clsCustomer getCustomer(int intCustomer)
{
SqlConnection objConnection = new SqlConnection();
DataSet ObjDataset = new DataSet();
SqlDataAdapter objAdapater = new SqlDataAdapter();
SqlCommand objCommand = new SqlCommand("Select * from Customer where CustomerId=" + intCustomer.ToString());
objConnection.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["ConnStr"].ToString();
objConnection.Open();
objCommand.Connection = objConnection;
objAdapater.SelectCommand = objCommand;
objAdapater.Fill(ObjDataset);
clsCustomer objCustomer = new clsCustomer();
objCustomer.CustomerCode = ObjDataset.Tables[0].Rows[0][0].ToString();
objCustomer.Customer = ObjDataset.Tables[0].Rows[0][1].ToString();
objConnection.Close();
return objCustomer;
}
}
and my page.xaml.cs:
public Page()
{
InitializeComponent();
ServiceCustomerClient obj = new ServiceCustomerClient();
obj.getCustomerCompleted += new EventHandler<getCustomerCompletedEventArgs>(DisplayResults);
obj.getCustomerAsync(1);
}
void DisplayResults(object sender, getCustomerCompletedEventArgs e)
{
LayoutRoot.DataContext = e.Result;
}
how can I insert a value into my dayabase right from my page.xaml.cs? how can I make a connection between service and xaml objects and functions?
thanks

The Page.xaml.cs file is not autogenerated in a standard silverlight project (beyond it's initial creation via template), so any changes you make to the class will persist.
If your current project does some autogen of xaml classes then you can use the partial class feature of C# Partial Classes in C# Guide to add to the class without worrying that the autogen will remove your additions.

You would need to add another method within your service class that performs the insert, and then pass it the values from your form.
public class ServiceCustomer : IServiceCustomer
{
public clsCustomer getCustomer(int intCustomer)
{
...
}
public void addCustomer(clsCustomer newCustomer)
{
//Code to add the customer to the database
}
}
to call this from your code you could use the following code, all calls to the service in silverlight are Asynchronous calls therefore they are called in a seperate thread but since the following call has no return there is no need for a completed event handler.
public void foo
{
clsCustomer cust = new clsCustomer();
//Create your customer object here
ServiceCustomerClient obj = new ServiceCustomerClient();
obj.AddCustomerAsync(cust);
}
this function could then be called when ever you want to add a customer, E.g. when a button is clicked
public void somebutton_Click(object sender, RoutedEventArgs e)
{
foo();
}
If you need any more information let me know.

Related

Telerik Reports parameters from WindowsForm Codebehind to Report

I'm working on a Windows Forms Application where I want to load Reports into a Reportviewer after a click on a Button.
This is the Event that gets triggered by pressing on the button in the Code behind of the Windows Form:
private void button1_Click(object sender, EventArgs e)
{
Telerik.Reporting.InstanceReportSource reportSource = new
Telerik.Reporting.InstanceReportSource();
reportSource.ReportDocument = new Reportlibrary.Report1();
reportSource.Parameters.Add(new Telerik.Reporting.Parameter("OrderNumber","123456789"));
reportViewer1.ReportSource = reportSource;
reportViewer1.RefreshReport();
}
The problem now is that I have no Idea how I can access / get the parameter I added before Refreshing the Reportviewer.
The Report already has set a Datasource. I don't know if this matters.
This is what I have right now. I've tried everything and I'm just not getting further.
public Report1()
{
InitializeComponent();
Position[] all = new Position[]{
new Position("Test", "Test","test"),
};
this.DataSource = all;
MessageBox.Show("Number: " +
this.Report.ReportParameters["OrderNumber"].Value.ToString());
}
Is there any way to get this parameter straight after InitializeComponent(); ?
Do I need to add another Event to the report to access it? If yes which on is the best way to do this?
Any help very apreciated.
Thank you
Set the parameters of the report on an instance of the report itself (not the report source), such as:
TopPageViews report = new TopPageViews();
report.ReportParameters["StartDate"].Value = new DateTime(2013, 3, 1);
report.ReportParameters["EndDate"].Value = new DateTime(2013, 3, 1);
InstanceReportSource reportSource = new InstanceReportSource();
reportSource.ReportDocument = report;
this.reportViewer1.ReportSource = reportSource;
this.reportViewer1.RefreshReport();
In your report constructor, after InitializeComponent, subscribe a handler to the ItemDataBinding event:
this.ItemDataBinding += TopPageViews_ItemDataBinding;
And in your handler, you can obtain the value as you normally would:
DateTime startDateParm = (DateTime)this.ReportParameters["StartDate"].Value;
You can use the debugger to see the value.
i know its an old question but after experiencing the same issue this how i did it and passed two parameter of date.
private void button1_Click(object sender, EventArgs e)
{
Report2 report = new Report2();
report.ReportParameters["datefrom"].Value
=dateTimePicker1.Value;
report.ReportParameters["dateto"].Value = dateTimePicker2.Value;
var rSource = new InstanceReportSource();
rSource.ReportDocument = report;
reportViewer1.ReportSource = rSource;
reportViewer1.RefreshReport();
}

Ninject ActivationException in WinForms application

I am working on a project to implement DI (using Ninject) into an existing WinForms application, however I have hit a few issues and my knowledge of working with DI in WinForms is limited at best, however I have successfully used it several times in MVC projects.
I get this message when trying to create a form that has a constructor that requires an interface of a repository:
Error activating IProductionRepository
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency IProductionRepository into parameter
productionRepository of constructor of type Main
1) Request for Main
I have searched on the web, but most of the articles I have read on this error either a dealing with much more complicated setups or are regarding parameter injection, which I am not sure is the issue here.
I have a form that is to launch the form that is to use DI (the error occurs on the kernel.Get call:
Private Sub txt_Click(sender As System.Object, e As System.EventArgs) Handles txt.Click
Try
Dim kernel As Ninject.IKernel =
New Ninject.StandardKernel(New NinjectFactory())
Dim form As Main = kernel.Get(Of Main)()
form.ConnectionString = App.pstrConnectString
form.ShowDialog(Me)
Catch ex As Exception
Support.ErrorHandler.ReportError(ex.Message, ex, True)
End Try
End Sub
I have my NinjectFactory with the correct binding (and several other commented out attempts):
public class NinjectFactory : NinjectModule
{
private IKernel _ninjectKernel;
public NinjectFactory()
{
_ninjectKernel = new StandardKernel();
}
public override void Load()
{
//_ninjectKernel.Bind(typeof(IRepository<>))
// .To(typeof(GenericRepository<>));
//_ninjectKernel.Bind(typeof(IProductionRepository))
// .To(typeof(ProductionRepository));
_ninjectKernel.Bind<IProductionRepository>().To<ProductionRepository>();
}
}
Finally I have the form I am trying to launch:
private IProductionRepository _productionRepository;
public string ConnectionString
{
get
{
return _connectionString;
}
set
{
_connectionString = value;
}
[Inject]
public Main(IProductionRepository productionRepository) : this()
{
this._productionRepository = productionRepository;
}
public Main()
{
InitializeComponent();
}
This is how I have used Ninject in MVC projects before and I haven't had an issue, however obviously there is something different regarding WinForms.
Any help would be greatly appreciated.
I suggest to use single point of dependency resolution, know as Composition Root, suggested by Mark Seemann (#mark-seemann) in his great book Dependency Injection in .NET. Your CompositionRoot might look like this:
public class CompositionRoot
{
private static IKernel _ninjectKernel;
public static void Wire(INinjectModule module)
{
_ninjectKernel = new StandardKernel(module);
}
public static T Resolve<T>()
{
return _ninjectKernel.Get<T>();
}
}
public class ApplicationModule : NinjectModule
{
public override void Load()
{
Bind(typeof(IRepository<>)).To(typeof(GenericRepository<>));
}
}
You can wire them in Program
CompositionRoot.Wire(new ApplicationModule());
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(CompositionRoot.Resolve<Form1>());
Now your button handler could look like this:
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(_productionRepository.ToString());
}
Note: if you want to test your application with different dependencies, which is probably the case, then you create another module with different wiring configuration. In tests you will have another wiring logic with stubs and mocks.
I also don't like NInject attributes on my model and if you use constructor injection - you can get rid of them. My entities are simple POCOs.
public interface IProductionRepository
{
}
public class ProductionRepository : IProductionRepository
{
public override string ToString()
{
return "Foo";
}
}
Mark also makes a great case for WinForms with DI pattern and how it can be implemented, i really suggest his book.

Is there a command to check to see if a database exists from Entity Framework?

I may have worded the question poorly but in my global.asx file i use
if (System.Diagnostics.Debugger.IsAttached)
{
var test = new TestDbSeeder(App_Start.NinjectWebCommon.UcxDbContext);
test.seed();
}
This checks to see if the debugger is attached and runs my test seeder so that my acceptance tests always pass.
I need to check to see if the database exists as well and if not run this code first:
var test2 = new DataSeeder();
test2.Seed(App_Start.NinjectWebCommon.UcxDbContext);
This dataseeder is the actual data that has to always be in the database. Is there a command to check if the database exists so that I can run that code block. Thanks!
Will the Database.Exists method work for you?
if (!dbContext.Database.Exists())
dbContext.Database.Create();
Edit #1 to answer comment
public class DatabaseBootstrapper
{
private readonly MyContext context;
public DatabaseBootstrapper(MyContext context)
{
this.context = context;
}
public void Configure()
{
if (context.Database.Exists())
return;
context.Database.Create();
var seeder = new Seeder(context);
seeder.SeedDatabase();
}
}
That should do exactly what you want. In your global.asax file...
public void Application_Start()
{
var context = ...; // get your context somehow.
new DatabaseBootstrapper(context).Configure();
}
In Entity Framework Core it works like this:
namespace Database
{
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
public partial class MyContextClass
{
/// <summary>
/// Checks if database exists
/// </summary>
/// <returns></returns>
public bool Exists()
{
return (this.Database.GetService<IDatabaseCreator>() as RelationalDatabaseCreator).Exists();
}
}
}
Make sure the class name equals your database Context class name and is in the same namespace.
Use it like this:
var dbExists = (MyContextClass)db.Exists()
Source: StackOverflow Answer

Using stored procedures (Linq-to-SQL, not EF) in WCF RIA - Silverlight 4

For the love of heaven and earth I really wish someone could help me out with this issue. It seems everyone has something to say about EF but nothing about Linq-to-SQL.
I am trying to grab some data from my table via a stored procedure, believe me, that's all.
I added the Linq-to-SQL model (LAMP.dbml)
added the stored procedure (getAffectedParcel) from the server explorer. getAffectedParcel takes 2 strings as parameters
Build the application.
Added a domain service class (LAMPService)
Selected the (LAMPDataContext) as the data context class (normally I would tick generate metadata, but since I am not working with tables it's not enabled for ticking)
Added the following function to the LAMPService.cs:
public IEnumerable < getAffectedParcelResult > GetTheAffectedParcels(String v, String vf)
{
return this.DataContext.getAffectedParcel(v, vf).AsEnumerable();
}
Added the following code to a Silverlight page in an attempt to consume the stored procedure:
LAMPContext db = new LAMPContext();
try
{
var q = db.GetTheAffectedParcels("18606004005", "").Value;
foreach (getAffectedParcelResult GAP in q)
{
MessageBox.Show(GAP.Owner);
}
}
catch (Exception ex)
{
MessageBox.Show (ex.Message.ToString());
}
Build and run application. An error occurs stating:
Object reference not set to an instance of an object.
I have tried ~1000,000 ways to see if this thing would work, but to no avail. Please don't tell me to use Entity Framework, I want to use Linq-to-SQL. Can someone (anyone) help me out here.
//houdini
Calling a stored procedure from the Silverlight client happens in the Async world. Let's consider an example from the AdventureWorks database...
Here's what the Domain Service method looks like. It is calling the EF on a stored procedure in the database called 'BillOfMaterials'.
public IQueryable<BillOfMaterial> GetBillOfMaterials()
{
return this.ObjectContext.BillOfMaterials;
}
Back on the client side, here is the code for setting up the call...
public GetSp()
{
InitializeComponent();
DomainService1 ds1 = new DomainService1();
var lo = ds1.Load(ds1.GetBillOfMaterialsQuery());
lo.Completed += LoCompleted;
}
First, the Domain Service is created, and then it is used to load the results of the stored procedure. In this particular case, the result of this is an instance of 'LoadOperation'. These things are async, so the LoadOperation needs to have a callback for when it is finished. The callback code looks like this...
public ObservableCollection<BillOfMaterial> MyList { get; set; }
void LoCompleted(object sender, EventArgs e)
{
LoadOperation lo = sender as LoadOperation;
if(lo!=null)
{
MyList = new ObservableCollection<BillOfMaterial>();
foreach(BillOfMaterial bi in lo.AllEntities)
{
MyList.Add(bi);
}
dataGrid1.ItemsSource = MyList;
}
}
In this method, the 'sender' is dereferenced into the LoadOperation instance, and then all the goodies from the database can be accessed. In this trivial example, a list is built and passed to DataGrid as the ItemsSource. It's good for understanding, but you would probably do something else in practice.
That should solve your problem. :)
The best advice I can give on Silverlight and RIA is never do ANYTHING on your own until you have tried it in AdventureWorks. You will just waste your time and beat your head against the wall.
Firstly, it seems like your DomainService code is written for Invoke() rather than Query(). You should use Query as it enables you to update data back to the server.
Solution: you should add a [Query] attribute to GetTheAffectedParcels on the domain service.
[Query]
public IQueryable<Parcel>
GetTheAffectedParcels(string ParcelNumber, string LotNumber)
{
// etc.
}
Secondly, RIA Services needs to know which is the primary key on the Parcel class.
Solution: Apply a MetadataType attribute to the Parcel class, which allows you to add metadata to the Parcel class indirectly, since it is generated by Linq2Sql and you couldn't add annotations directly to the ParcelId - it'd get wiped away.
[MetadataType(typeof(ParcelMetadata)]
public partial class Parcel
{
}
public class ParcelMetadata
{
[System.ComponentModel.DataAnnotations.Key]
public int ParcelId {get; set; }
}
Thirdly, modify your client like this. Instead try this on the Silverlight client:
LAMPContext db = new LAMPContext();
try
{
var q = db.GetTheAffectedParcelsQuery("18606004005", "");
db.Load(q, (op) =>
{
if (op.HasError)
{
label1.Text = op.Error.Message;
op.MarkErrorAsHandled();
}
else
{
foreach (var parcel in op.Entities)
{
// your code here
}
}
}
}
catch (Exception ex)
{
label1.Text = op.ex.Message;
}
Much thanks to Chui and Garry who practically kicked me in the right direction :) [thanks guys...ouch]
This is the procedure I finally undertook:
-After adding the data model(LINQ2SQL) and the domain service, I created a partial class [as suggested by Chui] and included the following metadata info therein:
[MetadataTypeAttribute(typeof(getAffectedParcelResult.getAffectedParcelResultMetadata))]
public partial class getAffectedParcelResult
{
internal sealed class getAffectedParcelResultMetadata
{
[Key]
public string PENumber { get; set; }
}
}
Then, Adjusted the Domain Service to include the following:
[Query]
public IQueryable<getAffectedParcelResult> GetTheAffectedParcels(string v, string vf)
{
// IEnumerable<getAffectedParcelResult> ap = this.DataContext.getAffectedParcel(v, vf);
return this.DataContext.getAffectedParcel(v, vf).AsQueryable();
}
Then Build the app, afterwhich the getAffectedParcelResult store procedure appeared in the Data Sources panel. I wanted to access this via code however. Therefore, I accessed it in silverlight [.xaml page] via the following:
LAMPContext db = new LAMPContext();
var q = db.GetTheAffectedParcelsQuery("18606004005", "");
db.Load(q, (op) =>
{
if (op.HasError)
{
MessageBox.Show(op.Error.Message);
op.MarkErrorAsHandled();
}
else
{
foreach (getAffectedParcelResult gap in op.Entities)
{
ownerTextBlock.Text = gap.Owner.ToString();
}
}
},false);
This worked nicely. The thing is, my stored procedure returns a complex type so to speak. As of such, it was not possible to map it to any particular entity.
Oh and by the way this article helped out as well:
http://onmick.com/Home/tabid/154/articleType/ArticleView/articleId/2/Pulling-Data-from-Stored-Procedures-in-WCF-RIA-Services-for-Silverlight.aspx

Failing to display a custom WPF dialog box more than one time

I am trying to display a custom dialog box multiple times using the following code:
TestWindow newTestWindow = new TestWindow(test);
newTestWindow.Owner = this;
newTestWindow.ShowDialog();
And I get the following exception when running the code above for the 2nd time:
Specified element is already the logical child of another element. Disconnect it first.
Chances are you are trying to display the same element in both dialogs (maybe the test parameter)? You would need to disconnect the element from the dialog when it's closed, so that it can be used in any subsequent dialogs.
Works fine for me:
public partial class MainWindow : Window
{
private Test _newTestWindow;
public MainWindow()
{
InitializeComponent();
Loaded += new RoutedEventHandler(OnLoaded);
}
private void OnLoaded( object sender, RoutedEventArgs e )
{
_newTestWindow = new Test { Owner = this };
_newTestWindow.ShowDialog();
_newTestWindow = new Test { Owner = this };
_newTestWindow.ShowDialog();
}
}

Resources