PDA

View Full Version : یه مشکل بامزه در کنترل های سفارشی



manager
جمعه 01 دی 1385, 22:37 عصر
سلام

من به یه مشکل بر خوردم که نتونستم حل کنم، گفتم شاید کسی بتونه اینجا کمکم بکنه.
شرح ماجرا از این قرار است که من یه Custom Control نوشتم که طرز کارش شبیه به کنترل Panel هست با این تفاوت که دور محتویات خود (کنترل های درون خود) در هنگام Render ، جهت تزئین یک جدول ایجاد می کند و در چهارگوشه آن عکس های کوچکی قرار می دهد و علاوه بر عکس ها یک کادر هم رسم می کند. مثل شکل زیر :


http://i17.tinypic.com/30a43nr.jpg


خوب این کنترل ما از Panel به ارث می بره و کار ما رو بسیار آسون می کنه ولی یه مشکل کجاست ؟!
من به دو صورت می تونم عمل Rendering رو انجام بدم. یک راه اینکه به صورت کثیف کد های HTML رو که جدول رو تولید می کند رو در داخل متد RenderContents قرار بدم. مثلا :


output.Write("<table ....> some html code ...");
base.RenderContent(output);
output.Write("... some html code ..</table>");
خوب به محل قرار گیری متد base.RenderContent نگاه کنید که چگونه با جایگیری در بین رشته ها عمل Render سایر کنترل ها را تحریک می کند.
خوب روش بعدی استفده از متد CreateChildControls هست و به این صورت که با استفاده از کنترل های Table, TableRow وTableCell و Image به هدف خودم برسم. روش دوم خیلی کاراست و خیلی هم شفاف و تمیز.
سوال : چگونه کنترل های داخلی یا همان کنترل هائی که داخل Panel قرار دارد را دقیقا در یک مکان مشخص Render کنم ؟
به عنوان مثال فرض کنید با توجه به شکل نیاز است که کنترل های Panel را داخل سلول مرکزی Render کنم، با استفاده از روش قبلی این امکان وجود داشت ولی حالا که کنترل ها رو به صورت غیر رشته ای و HTMLای دارم ایجاد می کنم چه کار باید بکنم ؟

ذکر این نکته هم خالی از لطف نیست که من چند روش رو امتحان کردم ولی جواب نداد. مثلا کنترل های موجود در

base.Controls رو به centerCell.Controls اضافه کردم ولی جواب نداد، با این روش فقط کنترل های Literal به centerCell اضافه می شد.

reza_rad
شنبه 02 دی 1385, 06:48 صبح
نمی دونم دقیقا همینو میگی یا نه...
ولی شما می تونی یک کنترل از نوع table html توی متد createchildcontrols ایجاد کنی(new ). و بعد Tablerow و tablecell رو هم new کنی و یک جدول رو طوریکه می خواهی با اینها بسازی.
یعنی باید tablerow , table cell رو به جدول add کنی.و...
حالا هر جا خواستی کنترلهات قرار بگیرند اونها رو به tablecell اونجا add کنی.
در نهایت هم جدول رو به base اضافه کنی.

manager
شنبه 02 دی 1385, 08:57 صبح
جناب آقای راد ممنون از توجهتون من دقیقا در روش دومی که توضیح دادم همین کار رو کردم :




public class Panel : System.Web.UI.WebControls.Panel
{
...
protected void CreateChildControls()
{
...
Table t = new Table();
t.ID = this.ID + "tbl";

TableRow uprow = new TableRow(); // Up Row
t.Rows.Add(uprow);

TableCell lucell = new TableCell(); // Left Up Cell
lucell.Attributes.Add("Height", "6");
uprow.Cells.Add(lucell);

HtmlImage htmilu = new HtmlImage();
...
lucell.Controls.Add(htmilu);
...
_cmcell = new TableCell();// Center Middle Cell
_cmcell.BackColor = this.BackColor;
for (int i = 0; i < base.Controls.Count; ++i)
{
_cmcell.Controls.Add(base.Controls[i]);
}
middleRow.Cells.Add(_cmcell);
...
this.ChildControlsCreated = true;
}

protected override void RenderContents(HtmlTextWriter output)
{
base.RenderContents(output);
}
}


همون طور که مشاهده می کنید دقیقا مشکل من الان اینکه چه طوری کنترلهای داخل Panel رو دقیقا در سلول وسط Render کنم ؟

reza_rad
شنبه 02 دی 1385, 10:12 صبح
بازم من نگرفتم:(

ببینید شما توی سلول وسط جدولتون می تونید کنترل add کنید یا نه؟
اگه می تونید و مشکل اینه که alignment رو تنظیم کنید می تونید از property های زیر استفاده کنید:


tcel.HorizontalAlign = HorizontalAlign.Center
tcel.VerticalAlign = VerticalAlign.Middle


اگه مشکل اینه که توی سلول وسط کنترل اضافه نمیشه. کل کد رو بذارید اینجا شاید مشکل جای دیگه ای باشه.

manager
شنبه 02 دی 1385, 14:14 عصر
نه برادر اینقدر ها هم ساده نیست وگرنه اینجا تاپیک نمی ذاشتم. شما اصلا از مد دیزاین بیا بیرون.
ببیند تو سلول وسط می تونم کنترل اضافه کنم ولی مشکل اینجاست که بعضی کنترل های اضافه نمی شه. من کنترل ها رو از base.Controls می خونم چون می خوام تمام کنترل های داخل Panel، داخل سلول وسطی درج بشن. خوب مشکل اینجاست که کنترل های وبی مثل TextBox و یا CheckBox به سلول وسطی اضافه نمی شه ! و فقط متن هایی که داخل کنترل Panel نوشته شده به سلول وسطی درج می شن. در نهایت پس از اجرای برنامه به جای اینکه تصویری شبیه به زیر تولید بشه :


http://i17.tinypic.com/2mebek1.jpg

این تصویر خروجی ما خواهد بود.

http://i16.tinypic.com/4bsseo8.jpg

در تصویر به وضوح نشان داده شده که کنترل های وبی به سلول اضافه نشدن (معلوم نیست با چه علتی)
قطعه کدی که کار اضافه کردن کنترل ها رو می کنه در جواب قبلی Bold کردم.
جالبه بدونید که اجازه lمی داد this (و یا base) رو به عنوان کنترل به Controls سلول مرکزی اضافه کنم، همه چیز حل بود.

من خیلی سعی کردم با تصویر و توضیح سوالم رو واضح شرح بدم ولی اگر باز مبهم بود بگید بیشتر شرح بدم. در نهایت اگر نمی دونستید مشکلم چه طوری حل می شه یه چندتا رفرنس بدید که نحوه رندر کردن کنترل های سفارشی رو به طور کامل و مفصل شرح داده باشه (حتی اگر یه کتاب باشه)

SalarSoft
شنبه 02 دی 1385, 18:26 عصر
چرا از UserControl استفاده نمی کنی (تو بیشتر سایت ها برای چند پوسته بودن مورد استفاده است).
یا یه روش دیگه از فایل Html . که البته اینجا من روش html رو می گم.

فایل test.html رو ایجاد کن



<table style="width:100%;"><tr>
<tr>
<td >[:Body:]</td>
</tr>
</table>


لازم خواهد بود تا کنترل سفارشی مان را به صورت دستی رند کنیم پس:


public static string RenderControls(ControlCollection ctrls)
{
if (ctrls == null) return "";
StringWriter strwriter = new StringWriter();
HtmlTextWriter writer = new HtmlTextWriter(strwriter);
foreach (Control ctrl in ctrls)
{
ctrl.RenderControl(writer);
}
string result = strwriter.ToString();
strwriter.Close();
writer.Close();
return result;
}



خواندن محتویات فایل:


public static string LoadHtml(string name)
{
string html = File.ReadAllText(HttpContext.Current.Server.MapPat h(name));
}


و سر انجام مراحل رندر کنترل را باز نویسی می کنیم:


protected override void Render(HtmlTextWriter writer)
{
const string tagContent = "[:Body:]";
base.Render(writer);
string theme = LoadHtml("test.html");
string content =RenderControls( this.Controls);
writer.Write(theme.Replace(tagContent, content));
theme = null;
content = null;
}


به شخصه روش UserControl ها رو بیشتر می پسندم چونکه امکان مانور روش زیاد است و حافظه کمتری رو کنترل ها و تم های بزرگ برای asp.net داره.
اگر مایل باشید یه نمونه برای آن هم مثال بزنم.

titbasoft
شنبه 02 دی 1385, 19:35 عصر
شرمنده فرصت نکردم با دقت بخونم، اگر یک کنترل به کالکشن Controls اضافه می کنید، تا زمانی که رندر نشن، نمی بیندشون، مثال:


Protected Overrides Sub Render(ByVal w As System.Web.UI.HtmlTextWriter)
Dim s as new ServerControl
Controls.Add(s)
RenderChildren(w)
End Sub

Protected Overrides Sub RenderChildren(ByVal w As System.Web.UI.HtmlTextWriter)
Dim i As Integer
For i = 0 To Controls.Count - 1
Controls(i).RenderControl(w)
Next
End Sub

manager
شنبه 02 دی 1385, 20:56 عصر
چرا از UserControl استفاده نمی کنی (تو بیشتر سایت ها برای چند پوسته بودن مورد استفاده است).

نه کنترل کاربری جواب نمی ده می خوام مثل Panel Control عمل کنه. بالا که توضیح دادم عزیز دل برادر.
روش بعدی هم که معرفی کردی از همون روش اول من یعنی کد کثیف پیروی می کنه نه اون هم مورد کاربرد نیست در ضمن موقع جابه جائی هم باید یه فایل Html رو جابجا بشه و هم یه فایل اسمبلی. ولی روش جالبی بود ازت ممنونم.


شرمنده فرصت نکردم با دقت بخونم، اگر یک کنترل به کالکشن Controls اضافه می کنید، تا زمانی که رندر نشن، نمی بیندشون، مثال:
من منظورتون رو متوجه نشدم. اگر می شه بیشتر توضیح بدین.

titbasoft
یک شنبه 03 دی 1385, 11:10 صبح
Public Class MyPanel
Inherits WebControl

Dim tbcMiddleCell As New TableCell


Protected Overrides Sub Render(ByVal w As System.Web.UI.HtmlTextWriter)
Dim tbl As New Table
Dim row As New TableRow

tbl.BackColor = Color.BlueViolet
tbl.BorderWidth = Unit.Pixel(3)

row.Cells.Add(tbcMiddleCell)
tbl.Rows.Add(row)

MyBase.Controls.Add(tbl)
RenderChildren(w)
End Sub

Protected Overrides Sub RenderChildren(ByVal w As System.Web.UI.HtmlTextWriter)
Dim i As Integer
For i = 0 To MyBase.Controls.Count - 1
MyBase.Controls(i).RenderControl(w)
Next
End Sub


Public Overrides ReadOnly Property Controls() As System.Web.UI.ControlCollection
Get
Return tbcMiddleCell.Controls
End Get
End Property
End Class


طریقه نمونه گیری هم که کاملا عادیه:

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim p As New MyPanel
p.Controls.Add(New Button)
Panel1.Controls.Add(p)
End Sub

rezaei manesh
یک شنبه 01 بهمن 1385, 11:47 صبح
سلام خدمت اساتید محترم
من یک کنترل روی فرم قرار دادم بعد کنترل های دیگرم رو توش گذاشتم
بعد در فرم لود


Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim p As New MyPanel
'.....?
Panel1.Controls.Add(p)
End Sub

این کد رو گذاشتم
در ضمن کلاس MyPanel
رو هم درست کردم اما هنوز مشکل پست شماره 5 جناب manager رو دارم!
آیا من حتما باید کنترل های خودم رو دستی بسازم ؟ یا اینکه نه یه جای کارم اراد داه
در ضمن اگه جای .... که گذاشتم از یه کنترلی که همون جا مثل آقای راد ساختم بسازم درست کار می کنه
مشکل من در کجاست
چندین بار هم همه پست های این تاپیک رو خوندم اما نتونستم مشکلم رو حل کنم؟

titbasoft
یک شنبه 01 بهمن 1385, 13:45 عصر
در مورد MyPanel بیشتر توضیح بدید یا کدش رو بزارید تا ببینم

rezaei manesh
یک شنبه 01 بهمن 1385, 14:37 عصر
این همون کلاسی که شما ساختید دیگه
من فقط یه فایل از نوع کلاس به پروژه اضافه کردم و همه کدهای پست شماره 9 همین تاپیک(کد کلاس mypanel خودتان )رو تماماً در اونجا کپی کردم .
و بعد یک پنل معمولی روی فرم قرار دادم و بعد کنترل های خودم رو درونش گذاشتم و در pageload هم همون طور که گفتید عمل کردم اما ظاهرا فقط کنترل های درون panel قرار می گیرند که از روش زیر به کلاس mypanel اضافه شده باشند


Dim p As New MyPanel
p.Controls.Add(New Button)

titbasoft
یک شنبه 01 بهمن 1385, 15:03 عصر
هنوز متوجه نشدم مشکل کجاست، دقیاقا بگید مشکلتون چیه؟ چه کنترلهایی رو نمی بینید؟ اصلا هدف شما چیه؟



بعد کنترل های خودم رو درونش گذاشتچرا کنترل ها رو توی پنل معمولی گذاشتید؟ مگه نمی خواهید توی پنل سفارشی شما قرار بگیرند؟


فقط کنترل های درون panel قرار می گیرند که از روش زیر به کلاس mypanel اضافه شده باشندکدوم پنل؟ سفارشی (mypanel) یا پنلی که به عنوان Parent ی پنل سفارشی در نظر گرفتیم (panel1)؟ خوب این که طبیعیه.

rezaei manesh
یک شنبه 01 بهمن 1385, 19:36 عصر
چرا می خوام تویه پنل سفارشی بزارم
من فکر می کردم یک پنل معمولی با کنترل های مورد نیاز رو درست می کنم و بعد اینو به پنل سفارشی نسبت می دم که اشتباه فکر می کردم ظاهراً
من می خوام مانند شکل های صفحه قبل رو درست کنم .
حالا من باید همه کنترل ها(تکست باکس و لینک و ...) رو یکی یکی از طریق کد نویسی درست کنم . مکان هاشونو ست کنم و... بعد اونا رو به کنترل سفارشی اضافه کنم ؟
نمی شه یه طوری به شه کنترل سفارشی در موقع design روی صفحه نمایش داده بشه و من کنترل هامو از جعبه ابزار انتخاب کنم و اونجا بزارم طبق روال معمول ؟
اگه نشه که خیلی سخت می شه مخصوصا قرار دادن کنترل ها هر کدوم در جای خودش
من در نهایت از این روش برای 2 جا می خوام استفاده کنم یکی در حالت معمول یکی درItemTemplete دیتا لیست.

rezaei manesh
دوشنبه 02 بهمن 1385, 08:22 صبح
آقا من دیروز از طریقه سوال پرسیدن شما جواب رو گرفتم دیشب رفتم تونستم مشکل رو حل کنم
حالا فقط مونده که در دیتالیست ازش استفاده کنم که امشب می رم روش کار می کنم