|
I just want to know where to put the object model (the classes like customers, orders, ...) in the n-tier model.
Common , Data or business layer. (on msdn they put datasets is the common.
thanks
Jan
www.agilis.be
|
|
|
|
|
I'd prefer to put the object model you refer to in the DAL and use the provider pattern for those objects to get/set data in a data source (such as a database), effectively splitting up the data layer into two tiers (although that depends on your scope of a tier). The business layer typically defines how those objects interact with each other. Again, depending on your view of what comprises a tier, you might consider that those objects are either in the business layer or the data layer. Also keep in mind that N-tier isn't limited to 3 tiers.
For example, our next major version of our application that is currently being sketched out consists of many layers, such as a presentation layer, a business layer, a data objects layer coupled with a data provider layer, with a server layer to provide remotable data services for our implementation (while other companies can choose to override or replace whatever layer they want). It's a pretty fractured design, but a pretty big N-tier model allowing for maximum (IMO) extensibility.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
I'm sure there are many ways to solve this, and much has to do with taste.
For most applications I prefer a 3-tier solution: data, business and facade/presentation, but that is of course depending a lot on the scenario.
The data tier consists of two kinds of classes, none of them static:
1. The objects in the object model (usually maps to tables in a relational database). Those are very much like structures, with no logic in them, just data fields for transport. For example the Customer class. Take a look at xsd.exe to generate those out of schemas.
2. Factory/accessor classes that creates and delivers object model instances, or recieves object model instances. For example CustomerFactory (or CustomerDB if you don't like the "concrete factory" pattern analogy). Those classes contain logic for retrieving data and updating data. If the data resides in SQL server they handle connection objects and have all the insert, update and select in them (or SP's handle that). If the data comes from a web service, they contain web service consumer proxies etc.
Example of methods:
public Customer FindByCustomerID(int id)
public OperationResult Save(Customer[] customers)
I think the most important design decision for you to consider is that the data-tier should not be aware of the other tiers, and it shall reveal nothing about the actual data sources to the other tiers. It delivers the data to whoever needs it, period. Much more can be said about the details, and many books have been written on the subject. Good luck with your project.
Regards,
Björn Morén
Stockholm, Sweden
|
|
|
|
|
Thanks Björn
I had just read the "mastering XDE book from sybex" It had an overview of different patterns but i just couldn't fit the puzzle together.
Now it's coming clear to me.
If you ever need a favor, just yell
Greets from Belgium
Jan
www.agilis.be
|
|
|
|
|
using System;
namespace MBoard
{
///
/// Summary description for Class1.
///
public class Class1
{
public Class1()
{
string t;
int p;
t="11";
p= (int)t+1;
System.Diagnostics.Debug.WriteLine(p);
}
static void Main()
{
Class1 c=new Class1();
}
}
}
OK!! here i want to result as 12, not 111.
How could i get it?
|
|
|
|
|
Never mind!
Syntax
using System;
namespace MBoard
{
///
/// Summary description for Class1.
///
public class Class1
{
public Class1()
{
string t="123";
int p=1;
System.Diagnostics.Debug.WriteLine(int.Parse(t) + p);
}
static void Main()
{
Class1 c=new Class1();
}
}
}
|
|
|
|
|
You should put int.Parse , Convert.ToInt32 , or whatever you use in a try/catch block. Never trust user input! Always validate user input and expect the unexpected, even in throw-away utility projects (practice makes perfect!). Not validating input is the most common reason for all the viruses and worms.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
|
Sorry to post a Crystal Report question in here, but I don't know where else to ask it, since I'm using it in C#. I have no problem passing datasets to my report...everything works fine. BUT...I can't seem to find a way of passing a simple variable into my report. I just want to print 2 separate dates on my report, that definitely doesn't require an entire dataset just for 2 dates...but I don't know how to put them in my report. The closest I've come is using a parameter field...but then I have to input the dates in that dialog box that pops up, and I don't like that. I just want to do it programmatically so the user never knows how it happened. Any ideas? Thanks
|
|
|
|
|
parameter fields is exactly what you need.
Here is some howto (cut from visual studio help):
Parameter Fields Runtime Customization
You can support user input with parameters in Crystal reports. Such parameters can be used for a variety of purposes. For example:
Base a parameter on a database field and allow the user to specify values for that field to filter data in the report.
Apply conditional formatting to a report by using parameter fields.
Define sort order by using parameter fields.
The following example demonstrates how parameter field values can be set, through code, at runtime. It explains how to set two different parameters. The first is a multiple-value discrete parameter, and the second is a range value parameter.
To Modify Parameter Fields at Runtime
[C#]
ParameterFields paramFields = new ParameterFields ();<br />
ParameterField paramField = new ParameterField ();<br />
ParameterDiscreteValue discreteVal = new ParameterDiscreteValue ();<br />
ParameterRangeValue rangeVal = new ParameterRangeValue ();<br />
<br />
<br />
paramField.ParameterFieldName = "Customer Name";<br />
<br />
discreteVal.Value = "AIC Childrens";<br />
paramField.CurrentValues.Add (discreteVal);<br />
<br />
discreteVal = new ParameterDiscreteValue ();<br />
discreteVal.Value = "Aruba Sport";<br />
paramField.CurrentValues.Add (discreteVal);<br />
<br />
paramFields.Add (paramField);<br />
<br />
paramField = new ParameterField ();<br />
<br />
paramField.ParameterFieldName = "Customer ID";<br />
<br />
rangeVal.StartValue = 42;<br />
rangeVal.EndValue = 72;<br />
paramField.CurrentValues.Add (rangeVal);<br />
<br />
paramFields.Add (paramField);<br />
<br />
crystalReportViewer1.ParameterFieldInfo = paramFields;
|
|
|
|
|
threre is 2 simple way :
1- using textobject for sending value to your report:
create textobject with TextTimeFrom name(or desired name) then
in your code set value for TextTimeFrom textobject
...C# code
((TextObject)ReportOne.ReportDefinition.ReportObjects["TextTimeFrom"]).Text = "12:25";
....
this value is placed on your report because textobject will be placed on report area
if you want to send parameter to conitional approach use formula field and you can place formula field object on your form or not!
second way byy using formula fields
2-
create one formula field with YearValue(or desired name,YearValue just is sample name) name and then set that value in your code like this :
...C# code
ReportOne.DataDefinition.FormulaFields["YearValue"].Text= "value;
(ReportOne is your report ReportDocument object)
....
you see it is very simple just with one line coding
enjoy of it
|
|
|
|
|
I have written a user control, and displayed it on a web page. There is a server side application that is supposed to provide the user control the data. I can do this through setting a property of the user control. What I am stuck at is how to make the user control request data to the server side application.
A simple example. I have a user control with a label and a timer on it. On each timer tick, I want the user control to request the server side application to populate the label with the current time at the server.
|
|
|
|
|
The user control is not confined to the typical request/response mechanism of the web page in which it's embedded, so you can communicate with the server using Web Services or .NET Remoting (or some proprietary socket communication, which I wouldn't recommend). So while the page the user is viewing may be static (i.e., they haven't refreshed it) the user control is happilly communicating with the server.
Also, you could have the page using XMLHTTP (a scripting component, or automation server) and set properties/call methods on the user control so long as it exposes automation information through dispatch interfaces. See my old article on DevHood about this: User Controls for Windows and the Web[^].
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
TcpListener server =new TcpListener(9050);
TcpClient t=server.AcceptTcpClient();
please show me the way the get the ip address of client t.
thanks
|
|
|
|
|
Why don't you use a socket?
Socket socket = server.AcceptSocket();
IPEndPoint ep = socket.GetRemoteEndpoint();
IPAddress ipAddress = ep.Address;
String strIpAddress = ipAddress.ToString();
|
|
|
|
|
How can I handle (like e.Handle = true of keypress event) and let not to change the colum width of listview when the user click or drag the cloumn header of the listview.
Im makeing a custom control inherited for listview.
It is posible?
In other wors, can i let or not to change the with of columns of listview before happenn this event?
I Need to let the user to change this value in an valid range to not to show the horizontal scrollbar of the lisview.
Thank you!
La realidad no es más que impulsos eléctricos del cerebro - Morpheus
|
|
|
|
|
Use something similar to my last reply[^] to your similar question, only handle the HDN_ITEMCHANGING (-300 or -320 for *A and *W defs respectively) message and set Message.Result to new IntPtr(0) (FALSE ) to deny the change, or new IntPtr(1) (TRUE ) to allow the change.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Thank you again! I will try it.
La realidad no es más que impulsos eléctricos del cerebro - Morpheus
|
|
|
|
|
ok, it was not much simple for me.
Would you write to me a more especif sample code of your sugestion? Where and how to handle the HDN_ITEMCHANGING message and set Message.Result to new IntPtr(0)or new IntPtr(1) When I need?
I add your last code to my class and add and implement the DataListView_ColumnHeaderChanged.
Thank you!
La realidad no es más que impulsos eléctricos del cerebro - Morpheus
|
|
|
|
|
It really isn't hard and I think you'd learn best by figuring out why I did what I did. Note that the changes are very minor.
Also, in the future, you'd do best to reply to me instead of yourself, otherwise I won't receive a reply notification and may not see your message. It just so happened I did this time, but only because I noticed the old thread was longer than it should be as I happened to glance at it.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
ok, thank you. I will try it more, but this - interop with windows messages is new for me and its difulcult to me understand how works with this a n use its constants at this moment
I think I need to modify the WndProc because is there where i found m.result and HDN_ITEMCHANGEDW. I think I need to use the same message WM_NOTIFY and hdr.code == HDN_ITEMCHANGEDA || hdr.code == HDN_ITEMCHANGEDW becouse your last tip.
I do this to try but it does nothing. The colums change the width.
protected override void WndProc(ref Message m)<br />
{<br />
base.WndProc(ref m);<br />
if (m.Msg == WM_NOTIFY)<br />
{<br />
NMHDR hdr = (NMHDR)Marshal.PtrToStructure(m.LParam, typeof(NMHDR));<br />
if (hdr.hwndFrom == hWndHeader &&<br />
(hdr.code == HDN_ITEMCHANGEDA || hdr.code == HDN_ITEMCHANGEDW))<br />
{<br />
m.Result = new IntPtr(0);
<br />
NMHEADER header = (NMHEADER)<br />
Marshal.PtrToStructure(m.LParam, typeof(NMHEADER));<br />
<br />
int index = header.iItem;<br />
if (index >= 0 && index < Columns.Count)<br />
{<br />
ColumnHeader col = Columns[index];<br />
OnColumnHeaderChanged(new ColumnHeaderChangedEventArgs(col));<br />
}<br />
}<br />
}<br />
}
La realidad no es más que impulsos eléctricos del cerebro - Morpheus
|
|
|
|
|
The biggest change is that you must call base.WndProc after setting Message.Result to either TRUE (to allow resizing) or FALSE (to deny resizing). You do this by setting Result to new IntPtr(0) for FALSE , and new IntPtr(1) for TRUE (or define these as read-only fields, whatever you prefer). If you call base.WndProc first, the message is processed and the resizing is allowed. Besides the messages being defined to different values, the original code I posted is pretty much the same.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
I put m.Result = new IntPtr(0); firs before base.WndProc but still changin the width.
<br />
protected override void WndProc(ref Message m)<br />
{<br />
m.Result = new IntPtr(0);<br />
base.WndProc(ref m);<br />
if (m.Msg == WM_NOTIFY)<br />
{<br />
Thak you for your help!
La realidad no es más que impulsos eléctricos del cerebro - Morpheus
|
|
|
|
|
DO NOT set Message.Result to FALSE like that! You could screw-up anything. You only set it when the message in which you're interested comes through the message handler. There are potentionally hundreds of messages flying through your message handler while initializing, with many more passing through while the code is executing or even idle in some cases.
See my sample code that I posted which does work. I also mentioned that I mis-read the documentation - you actually pass TRUE (new IntPtr(1) ) to deny changing the column header width.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Actually, I have that backward: return TRUE to deny changes or FALSE to allow them. My bad. Also, something in base.WndProc is resetting the Message.Result back to 0, so you will have to call it first. Since I made a mistake, I'll post my modified source here:
using System;
using System.Drawing;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyKeyFile(@"C:\Proplanner.NET\KeyFile.snk")]
public class Test : Form
{
static void Main(string[] args)
{
bool b = true;
if (args.Length > 0)
{
try
{
b = bool.Parse(args[0]);
}
catch {}
}
Application.Run(new Test(b));
}
public Test(bool allowResizing)
{
SuspendLayout();
Text = "MyListView Test";
MyListView lv = new MyListView();
Controls.Add(lv);
lv.Dock = DockStyle.Fill;
lv.View = View.Details;
lv.AllowResizing = allowResizing;
lv.ColumnHeaderChanged += new ColumnHeaderChangedEventHandler(
lv_ColumnHeaderChanged);
ColumnHeader col1 = new ColumnHeader();
col1.Text = "One";
ColumnHeader col2 = new ColumnHeader();
col2.Text = "Two";
lv.Columns.Add(col1);
lv.Columns.Add(col2);
ResumeLayout();
}
private void lv_ColumnHeaderChanged(object sender,
ColumnHeaderChangedEventArgs e)
{
Console.WriteLine("Column {0} changed: new width = {1}",
e.ColumnHeader.Text, e.ColumnHeader.Width);
}
}
public class MyListView : ListView
{
private IntPtr hWndHeader;
private bool allowResizing = true;
public bool AllowResizing
{
get { return allowResizing; }
set { allowResizing = value; }
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
hWndHeader = SendMessage(Handle, LVM_GETHEADER, 0, 0);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_NOTIFY)
{
NMHDR hdr = (NMHDR)Marshal.PtrToStructure(m.LParam, typeof(NMHDR));
if (hdr.hwndFrom == hWndHeader)
{
if (hdr.code == HDN_ITEMCHANGINGA ||
hdr.code == HDN_ITEMCHANGINGW)
{
if (allowResizing) m.Result = FALSE;
else m.Result = TRUE;
}
else if (hdr.code == HDN_ITEMCHANGEDA ||
hdr.code == HDN_ITEMCHANGEDW)
{
NMHEADER header = (NMHEADER)
Marshal.PtrToStructure(m.LParam, typeof(NMHEADER));
int index = header.iItem;
if (index >= 0 && index < Columns.Count)
{
ColumnHeader col = Columns[index];
OnColumnHeaderChanged(
new ColumnHeaderChangedEventArgs(col));
}
}
}
}
}
public event ColumnHeaderChangedEventHandler ColumnHeaderChanged;
protected virtual void OnColumnHeaderChanged(ColumnHeaderChangedEventArgs e)
{
if (ColumnHeaderChanged != null)
ColumnHeaderChanged(this, e);
}
private const int WM_NOTIFY = 78;
private const int HDN_ITEMCHANGINGA = -300;
private const int HDN_ITEMCHANGINGW = -320;
private const int HDN_ITEMCHANGEDA = -301;
private const int HDN_ITEMCHANGEDW = -321;
private const int LVM_GETHEADER = 4127;
private static readonly IntPtr FALSE = new IntPtr(0);
private static readonly IntPtr TRUE = new IntPtr(1);
[StructLayout(LayoutKind.Sequential)]
public class NMHDR
{
public IntPtr hwndFrom;
[MarshalAs(UnmanagedType.U4)] public int idFrom;
[MarshalAs(UnmanagedType.U4)] public int code;
}
[StructLayout(LayoutKind.Sequential)]
public class NMHEADER
{
public IntPtr hwndFrom;
[MarshalAs(UnmanagedType.U4)] public int idFrom;
[MarshalAs(UnmanagedType.U4)] public int code;
public int iItem;
public int iButton;
public IntPtr pitem;
}
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg,
int wParam, int lParam);
}
public delegate void ColumnHeaderChangedEventHandler(object sender,
ColumnHeaderChangedEventArgs e);
public class ColumnHeaderChangedEventArgs : EventArgs
{
private ColumnHeader columnHeader;
public ColumnHeaderChangedEventArgs(ColumnHeader header)
{
columnHeader = header;
}
public ColumnHeader ColumnHeader
{
get { return columnHeader; }
}
} To test this, copy it and compile it then run the application. As you can see you can resize the column headers. Now execute the program passing "false" as a command-line parameter and you'll see that you can't resize the column headers.
Microsoft MVP, Visual C#
My Articles
|
|
|
|