TagSL框架設(shè)計(jì)(1)----先來點(diǎn)簡(jiǎn)介
開篇
最近在做一個(gè)Silverlight的框架。
噢,這是一個(gè)僅僅工作一年半的沒學(xué)歷的我做的!!
現(xiàn)在還在開發(fā)中..... 因最近領(lǐng)導(dǎo)要看。我想先寫一篇簡(jiǎn)單的文章來介紹我的這種TagSL編程。
事先聲明,這種編程與傳統(tǒng)的編程模式格格不入。不用ORM,不寫實(shí)體類,設(shè)計(jì)模式貌似沒有,甚至?xí)赬AML里寫Sql語句哦,并且強(qiáng)制要求沒特殊情況不能動(dòng)服務(wù)端的代碼啊!并且沒用WCF等高深技術(shù)啊!甚至于你會(huì)發(fā)現(xiàn)怎么我還提倡XAML文件用中文命名!............. 如果你是自認(rèn)為‘大?!牟⑶蚁矚g亂噴的人,請(qǐng)繞道,寒舍承受不了您大駕光臨。當(dāng)然,如果你有一定的編程經(jīng)驗(yàn),并愿意以平等的交流技術(shù)和建議的口吻來溝通,小弟感激不盡。因?yàn)檎胬碓睫q越明的。當(dāng)然也非常歡迎你提一些問題。我發(fā)誓會(huì)一一解答。
噢,這篇文章是一篇介紹性的文章,又或者你可以理解為我52天后要開源的框架的預(yù)告版。所以不是‘附帶源代碼實(shí)例’的。請(qǐng)見諒呵呵。
大綱
1、TagSL的核心目標(biāo)
2、把那些那么多的XAML放到服務(wù)端去。
3、那兩個(gè)牛逼的查詢對(duì)象樹的方法。
4、不寫實(shí)體類了?
5、一個(gè)表單開始....
6、怎么獲得表單的值?
7、這樣弄有啥好處?
8、約定大于配置??
1、TagSL的核心目標(biāo)
根據(jù)《TagSL配置文檔》(還在書寫中哈哈),將常見業(yè)務(wù)交給每個(gè)控件都有的Tag屬性(用JSON字符安文檔串描述業(yè)務(wù)),不常見的業(yè)務(wù)交給代碼后置。
(TagSL即Siverlight標(biāo)簽編程法,又或者叫Silverlight半配置編程法)
2、把那些那么多的XAML放到服務(wù)端去。
在有大型的Silverlight項(xiàng)目的時(shí)候,礙于天朝的網(wǎng)速,我們常常郁悶的問題就是項(xiàng)目越大,我們要使用的XAML文件越多。而XAML文件是一次打包到客戶端的。這樣導(dǎo)致XAML過大。并且如果一個(gè)項(xiàng)目有100個(gè)XAML文件。當(dāng)你修改了其中的一個(gè),要發(fā)布,也要將整個(gè)項(xiàng)目編譯一次才能看到效果。真麻煩??!
我的TagSL做的第一件事就是就將XAML放到服務(wù)端。放到某個(gè)特定的目錄下。在做實(shí)際項(xiàng)目開發(fā)的時(shí)候,每個(gè)單獨(dú)的界面都實(shí)時(shí)從服務(wù)端下載(包括樣式文件),下載到客戶端之后使用 XamlReader.Load方法形成對(duì)橡樹。
或許你會(huì)問,那代碼CS的文件呢?
我會(huì)寫一個(gè)方法,唯一的參數(shù),參數(shù)就是這個(gè)XAML文件形成的對(duì)橡樹,并在對(duì)橡樹形成之后執(zhí)行這個(gè)方法。...... 然后就OK 了。這樣會(huì)有兩個(gè)問題,1是這樣會(huì)不會(huì)比傳統(tǒng)的CS文件做代碼后置有些功能不能實(shí)現(xiàn)?
我的答案是是:如果你真正了解Silverlight,你會(huì)知道代碼CS文件能做到的,我的這種機(jī)制也能做到。因?yàn)閷?duì)橡樹的根傳過來了。我就能很輕易的操作這個(gè)對(duì)橡樹。而且因?yàn)槲业?span style="background-color: rgba(255, 255, 153, 1); color: rgba(153, 51, 102, 1)">TagSL編程在編碼過程中,要常常對(duì)XAML文件進(jìn)行更改,反之用C#代碼操縱對(duì)橡樹的方面不多(初步估計(jì)在8.5:1的樣子)。故在這樣的模式下,采用將XAML放在服務(wù)端是更好的。
3、那幾個(gè)牛逼的查詢對(duì)象樹的方法。
這個(gè)兩個(gè)方法我想不一定要在我的TagSL編程中。在其他的編程中同樣可以用到。
查找對(duì)橡樹可以查孩子和父輩。而要知道Silvlight對(duì)橡樹分為邏輯對(duì)橡樹和可視化對(duì)橡樹(至于其區(qū)別請(qǐng)自行百度,個(gè)人認(rèn)為這兩個(gè)概念灰常重要)。
在HTML里我們最喜歡Jqurey了,呵呵動(dòng)不動(dòng)就是$() 這樣去查找一個(gè)或者一些DOM元素。而在Silverlight里這樣的方法也是非常重要的。呵呵。
這兩個(gè)方法在我這個(gè)框架中用的非常的多,而我相信他對(duì)你的編碼也會(huì)有幫助,當(dāng)然這是初始版本的,注釋啥的都不全,若可以請(qǐng)等待一個(gè)月后的開源版本呵呵。
包含的方法主要有??梢暬瘜?duì)橡樹和邏輯對(duì)橡樹的 查詢孩子和父輩元素的方法。特別注意過濾條件的寫法噢 .... 呵呵
View Code
#region 可視化對(duì)象樹查詢方式--孩子
public static List<T> Inspect<T>(DependencyObject dpObj, Func<T, bool> filter) where T : class
{
List<T> objList = new List<T>();
if (filter == null)
filter = _T => {
return true;
};
Inspect<T>(0, dpObj, ref objList, filter);
return objList;
}
private static void Inspect<T>(int level, DependencyObject dpObj, ref List<T> list, Func<T, bool> filter) where T : class
{
if ((dpObj is T))
{
if (filter(dpObj as T))
list.Add(dpObj as T);
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dpObj); i++)
{
Inspect<T>(level + 1, VisualTreeHelper.GetChild(dpObj, i), ref list, filter);
}
}
#endregion
#region 對(duì)象樹查詢方式--孩子
/// <summary>
/// 查詢孩子,用邏輯對(duì)象樹
/// </summary>
/// <param name="Prent">根對(duì)象</param>
/// <param name="filter">過濾條件</param>
/// <param name="list">返回對(duì)象集合</param>
public static void getAllChild(DependencyObject Prent, Func<FrameworkElement, bool> filter, ref List<FrameworkElement> list)
{
if (((Prent is FrameworkElement)) && filter(Prent as FrameworkElement))
{
list.Add(Prent as FrameworkElement);
}
if (Prent is UserControl)
{
UserControl _contentControl = Prent as UserControl;
if (_contentControl.Content is DependencyObject)
getAllChild(_contentControl.Content as DependencyObject, filter, ref list);
}
if (Prent is ContentControl)
{
ContentControl _contentControl = Prent as ContentControl;
if (_contentControl.Content is DependencyObject)
getAllChild(_contentControl.Content as DependencyObject, filter, ref list);
}
if (Prent is Panel)
{
Panel p = Prent as Panel;
foreach (UIElement item in p.Children)
{
if (item is DependencyObject)
getAllChild(item as DependencyObject, filter, ref list);
}
}
if (Prent is ItemsControl)
{
ItemsControl p = Prent as ItemsControl;
foreach (var item in p.Items)
{
if (item is DependencyObject)
getAllChild(item as DependencyObject, filter, ref list);
}
}
}
public static List<T> getAllChild<T>(DependencyObject Prent, Func<T, bool> filter) where T : class
{
List<T> list_T = new List<T>();
if (filter == null)
filter = _frameworkElement => {
return true;
};
getAllChild<T>(Prent, filter, ref list_T);
return list_T;
}
public static void getAllChild<T>(DependencyObject Prent, Func<T, bool> filter, ref List<T> list) where T : class
{
if (((Prent is T)) && filter(Prent as T))
{
list.Add(Prent as T);
}
if (Prent is UserControl)
{
UserControl _contentControl = Prent as UserControl;
if (_contentControl.Content is DependencyObject)
getAllChild(_contentControl.Content as DependencyObject, filter, ref list);
}
if (Prent is ContentControl)
{
ContentControl _contentControl = Prent as ContentControl;
if (_contentControl.Content is DependencyObject)
getAllChild(_contentControl.Content as DependencyObject, filter, ref list);
}
if (Prent is Panel)
{
Panel p = Prent as Panel;
foreach (UIElement item in p.Children)
{
if (item is DependencyObject)
getAllChild(item as DependencyObject, filter, ref list);
}
}
if (Prent is ItemsControl)
{
ItemsControl p = Prent as ItemsControl;
foreach (var item in p.Items)
{
if (item is DependencyObject)
getAllChild(item as DependencyObject, filter, ref list);
}
}
}
#endregion
#region 查詢祖輩
public static void getAncestor(DependencyObject dobj, Func<FrameworkElement, bool> filter, ref List<FrameworkElement> _ancestor)
{
if ((dobj is FrameworkElement))
{
FrameworkElement parent = dobj as FrameworkElement;
if (filter(parent))
_ancestor.Add(parent);
if (parent.Parent is FrameworkElement)
{
getAncestor(parent.Parent as FrameworkElement, filter, ref _ancestor);
}
}
}
public static void getAncestor<T>(DependencyObject dobj, Func<T, bool> filter, ref List<T> _ancestor) where T : FrameworkElement
{
T parent = dobj as T;
if (filter == null)
filter = _T =>
{
return true;
};
if (dobj is T && filter(parent))
_ancestor.Add(parent);
if (dobj is FrameworkElement)
{
getAncestor<T>((dobj as FrameworkElement).Parent, filter, ref _ancestor);
}
}
public static List<T> getAncestor<T>(DependencyObject dobj, Func<T, bool> filter) where T : FrameworkElement
{
List<T> _ancestor = new List<T>();
getAncestor<T>(dobj, filter, ref _ancestor);
return _ancestor;
}
#endregion
4、不寫實(shí)體類了?
關(guān)于要不要實(shí)體類,實(shí)體類到底帶來了什么,我想我會(huì)再開博文呵呵。不過在這里要確定的一點(diǎn)是,在Silverlight里,不寫實(shí)體類是可以的,但實(shí)體類不能沒有!
因?yàn)镾ilerlight最重要的一點(diǎn)就是數(shù)據(jù)綁定。而這里數(shù)據(jù)源就一定需要是對(duì)象。而這里的對(duì)象大部分就是我們從數(shù)據(jù)庫中取出來的數(shù)據(jù)并放到實(shí)體類中的單個(gè)對(duì)象或者對(duì)象集合。
但是不寫實(shí)體類,怎么來‘對(duì)象呢’?-----反射!
View Code
#region 形成實(shí)體類
public static List<String> GetCoumsByJson(string Json)
{
List<String> str_list = new List<string>();
try
{
JsonValue ja = JsonArray.Parse(Json);
foreach (string item in (((JsonObject)(ja[0]))).Keys)
{
if (!str_list.Contains(item))
str_list.Add(item.ToUpper());
}
}
catch (Exception e)
{
DealWithExpception(e, "根據(jù)Json獲得要生成的實(shí)體類的列名的集合的時(shí)候出錯(cuò)了,JSON內(nèi)容為" + Json);
}
return str_list;
}
public static Type getTypeByStrList(List<String> str_list)
{
string classInfo = "";
str_list.ForEach((s) => {
classInfo += s;
});
if (TagSlUserControl._AllTypes.ContainsKey(classInfo))
{
return TagSlUserControl._AllTypes[classInfo];
}
string className = "TempType" + Guid.NewGuid().ToString().Replace('-', 'a');
try
{
#region 反射形成類型的初始工作
AssemblyName an = new AssemblyName("TempAssembly" + Guid.NewGuid());
AssemblyBuilder assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(
an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder typeBuilder = moduleBuilder.DefineType(className
, TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout
, typeof(object));
ConstructorBuilder constructor =
typeBuilder.DefineDefaultConstructor(
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName);
#endregion
#region 給類型加字段
foreach (string item in str_list)
{
Type type = typeof(string);
FieldBuilder fieldABuilder = typeBuilder.DefineField(item, type, FieldAttributes.Private);
fieldABuilder.SetConstant("");
PropertyBuilder propertyABuilder = typeBuilder.DefineProperty(item, System.Reflection.PropertyAttributes.None, type, null);
MethodBuilder getPropertyABuilder = typeBuilder.DefineMethod("get",
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
type,
Type.EmptyTypes);
ILGenerator getAIL = getPropertyABuilder.GetILGenerator();
getAIL.Emit(OpCodes.Ldarg_0);
getAIL.Emit(OpCodes.Ldfld, fieldABuilder);
getAIL.Emit(OpCodes.Ret);
//定義屬性A的set方法
MethodBuilder setPropertyABuilder = typeBuilder.DefineMethod("set",
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
null,
new Type[] { type });
//生成屬性A的set方法的IL代碼,即設(shè)置私有字段_a值為傳入的參數(shù)1的值
ILGenerator setAIL = setPropertyABuilder.GetILGenerator();
setAIL.Emit(OpCodes.Ldarg_0);
setAIL.Emit(OpCodes.Ldarg_1);
setAIL.Emit(OpCodes.Stfld, fieldABuilder);
setAIL.Emit(OpCodes.Ret);
//設(shè)置屬性A的get和set方法
propertyABuilder.SetGetMethod(getPropertyABuilder);
propertyABuilder.SetSetMethod(setPropertyABuilder);
}
#endregion
TagSlUserControl._AllTypes.Add(classInfo, typeBuilder.CreateType());
return TagSlUserControl._AllTypes[classInfo];
}
catch (Exception e)
{
string msg = "";
foreach (string item in str_list)
{
msg += item + ";";
}
DealWithExpception(e, "根據(jù)字段生成實(shí)體的時(shí)候錯(cuò)了,getTypeByStrList(),字段內(nèi)容為" + msg);
return "".GetType();
}
}
#endregion=
如我的代碼,其中有兩個(gè)方法。第一個(gè)是根據(jù)JSON數(shù)據(jù)形成一個(gè)List<String> 的集合,然后根據(jù)這個(gè)集合的‘字段’,遍歷形成一個(gè)實(shí)體類。當(dāng)然在這個(gè)時(shí)候必須要關(guān)注的是,反射會(huì)影響性能嗎?
我的回答是,不會(huì)!為什么呢?因?yàn)槲业姆瓷錂C(jī)制..... 呵呵 Emit不是蓋的!
當(dāng)然需要注意的是,這里的JSON數(shù)據(jù)是根據(jù)DataTable形成的。
而接下來我們只需要采取反序列化的方式,即可將數(shù)據(jù)放到這個(gè)實(shí)體里或者實(shí)體集合里。然后寫一個(gè) _panel.DataContext=實(shí)體或者實(shí)體集合... 即可。
5、舉例說明一個(gè)‘表單’的配置
如果你看到了這。我可以明確的告訴你,上面四點(diǎn)。其實(shí)就是我的TagSL編程的最核心的東西 呵呵。 如果說我這個(gè)框架用到了什么‘高深’的技術(shù)的話,上面幾點(diǎn)算是最高深的了呵呵。
下面直入主題。我們來配置一個(gè)簡(jiǎn)單的表單配置
下面就是我的界面的樣子 呵呵。
而配置XAML如下
View Code
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Tag=" {PKValue:'9A1D8CC2-8789-5B1C-ABB7-334C94F9FA51'} "
xmlns:Intersoft="http://intersoft.clientui.com/schemas"
xmlns:Converters="clr-namespace:Contacts_MVVM.Converters"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:design="clr-namespace:Contacts_MVVM.ViewModels"
x:Class="MyXaml.UserControl1" FontFamily="Arial,SimSun"
d:DesignWidth="640" d:DesignHeight="480">
<UserControl.Resources>
<Style x:Key="TextBoxStyle" TargetType="Intersoft:UXTextBox">
<Setter Property="Margin" Value="10,0,0,0"/>
<Setter Property="Height" Value="26.2"></Setter>
</Style>
<Style x:Key="FieldLabelStyle" TargetType="Intersoft:StylishLabel">
<Setter Property="Width" Value="80"/>
<Setter Property="HorizontalContentAlignment" Value="Right"/>
<Setter Property="Padding" Value="4,0"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Background" Value="{x:Null}"/>
<Setter Property="BorderBrush" Value="{x:Null}"/>
<Setter Property="Foreground" Value="#FF6F6D6D"/>
</Style>
<Style x:Key="FormStyle" TargetType="StackPanel">
<Setter Property="Orientation" Value="Horizontal"/>
<Setter Property="Margin" Value="0,2"/>
<Setter Property="MinHeight" Value="20"/>
</Style>
</UserControl.Resources>
<Grid>
<Grid Background="White" Tag=" {TableName: 'Test-Student', 'ControlType': 1} ">
<Intersoft:ExpandableGroupBox FontSize="14" Header="學(xué)生【基本信息】">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="42"/>
<RowDefinition Height="42"/>
<RowDefinition Height="42"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.33*"/>
<ColumnDefinition Width="0.33*"/>
</Grid.ColumnDefinitions>
<StackPanel Style="{StaticResource FormStyle}" Orientation="Horizontal" Grid.Row="0" Grid.Column="0">
<Intersoft:StylishLabel Style="{StaticResource FieldLabelStyle}" Content="姓名:" />
<Intersoft:UXTextBox Style="{StaticResource TextBoxStyle}" Width="180" Tag=" {ActField:'StudentName'} "/>
</StackPanel>
<StackPanel Style="{StaticResource FormStyle}" Orientation="Horizontal" Grid.Row="1" Grid.Column="0">
<Intersoft:StylishLabel Style="{StaticResource FieldLabelStyle}" Content="郵箱:" />
<Intersoft:UXTextBox Style="{StaticResource TextBoxStyle}" Width="180" Tag=" {ActField:'Email',RegEx:'\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*'} "/>
</StackPanel>
<StackPanel Style="{StaticResource FormStyle}" Orientation="Horizontal" Grid.Row="1" Grid.Column="1">
<Intersoft:StylishLabel Style="{StaticResource FieldLabelStyle}" Content="移動(dòng)電話:" />
<Intersoft:UXTextBox Style="{StaticResource TextBoxStyle}" Width="180" Tag=" {ActField:'Call'} "/>
</StackPanel>
<StackPanel Style="{StaticResource FormStyle}" Orientation="Horizontal" Grid.Row="0" Grid.Column="1" >
<Intersoft:StylishLabel Style="{StaticResource FieldLabelStyle}" Content="生日:" />
<Intersoft:UXDateTimePicker Margin="10,10,0,0" Width="180" Tag=" {ActField:'Birthday'} "/>
</StackPanel>
<StackPanel Style="{StaticResource FormStyle}" Orientation="Horizontal" Grid.Row="2" Grid.Column="1">
<Intersoft:StylishLabel Style="{StaticResource FieldLabelStyle}" Content="班級(jí):" />
<Intersoft:UXComboBox Height="22" Margin="10,0,0,0" Width="180" Tag=" {ActField:'ClassID',ShowField:'[Test-Class].ClassName'} ">
</Intersoft:UXComboBox>
</StackPanel>
<StackPanel Style="{StaticResource FormStyle}" Orientation="Horizontal" Grid.Row="2" Grid.Column="0">
<Intersoft:StylishLabel Style="{StaticResource FieldLabelStyle}" Content="年級(jí):" />
<Intersoft:UXComboBox Height="22" Tag=" {ShowField:'[Test-Grade].GradeName',CascadeSql:'
SELECT dbo.[Test-Class].ClassName, dbo.[Test-Grade].GradeName
FROM dbo.[Test-Class] INNER JOIN dbo.[Test-Grade] ON dbo.[Test-Class].GradeID = dbo.[Test-Grade].GradeID'
} "
Margin="10,0,0,0" Width="180">
</Intersoft:UXComboBox>
</StackPanel>
</Grid>
</Intersoft:ExpandableGroupBox>
<Intersoft:UXCommandBar Height="44" VerticalAlignment="Bottom" Grid.Row="1" FontSize="12">
<Intersoft:UXButton x:Name="btnSave" Tag=" {BtnType:'Save'} " Content="保存" Width="80" IsDefault="True"
DialogResult="None"/>
<Intersoft:UXButton x:Name="bbbbbbbbbbbbbbbbbbbbbbbbbbb" Content="取消" Width="80" IsCancel="True"/>
</Intersoft:UXCommandBar>
</Grid>
</Grid>
</UserControl>
首先我確定的一件事是,表單元素的容器一定是一個(gè)Pannl。(幾乎一定是Grid,呵呵)。
我們會(huì)在這個(gè)Pannl上配置(注意這里的配置即Tag的值)
{TableName: 'Test-Student', 'ControlType': 1}
這樣的話,我的控件初始化器(其實(shí)就是幾個(gè)方法)就會(huì)找到這個(gè)Pannel并根據(jù)ControlType為1 知道這是一個(gè)表單的容器。并知道這個(gè)表單對(duì)應(yīng)的表是Test-Student這個(gè)表。
接下來每個(gè)字段都回有相應(yīng)的配置。你會(huì)注意到幾乎都有{:''} 這個(gè)配置。這個(gè)配置我的用意就是告訴表單初始化器這個(gè)表單擁有的這個(gè)字段。還有日期字段。日期字段我的控件初始化器會(huì)自動(dòng)識(shí)別其為日期字段,并做響應(yīng)的轉(zhuǎn)換。當(dāng)然你會(huì)注意到還有下拉列表框。注意如果這個(gè)下拉列表框的值是由另一個(gè)表的話。配置的方法是這樣 ShowField:'[Test-Class].ClassName' 。即‘[表名].字段名’的方式。 這樣這個(gè)下拉列表框就會(huì)自動(dòng)的填充值。呵呵。
特別要注意以下幾點(diǎn)
A:我的服務(wù)端會(huì)根據(jù)表名自動(dòng)的知道每個(gè)表單的表的主鍵是哪一個(gè)。甚至我會(huì)根據(jù)表的字段信息查詢這個(gè)字段的非空屬性等等。
B:還有一些功能比如每個(gè)字段還可以加入正則表達(dá)式驗(yàn)證等等。而這些只需要在XAML的控件的Tag里加一個(gè)簡(jiǎn)單的配置而已呵呵。
C:而且如果你自信你會(huì)發(fā)現(xiàn)UserControl里有這么一個(gè)配置 Tag=" {PKValue:'9A1D8CC2-8789-5B1C-ABB7-334C94F9FA51'} "。呵呵,這個(gè)PKValue就是指當(dāng)前這個(gè)UserControl------這個(gè)樣的UserContrl我稱之為 Page,即一個(gè)界面。這個(gè)PKValue就是我定義的一個(gè)界面級(jí)別的值。 注意上圖我的那個(gè) 表單里頭的值就是通過這個(gè)主鍵找到的。當(dāng)然這么長的一個(gè)主鍵是不需要你配置呵呵。比如當(dāng)我們?cè)谝粋€(gè)列表當(dāng)中點(diǎn)擊某一條數(shù)據(jù)編輯的時(shí)候,我們的做法要將UserControl的Tag屬性賦值。就象我們?cè)贖TML的列表里點(diǎn)擊某條數(shù)據(jù)編輯一條記錄彈出一個(gè)窗口我們要URL傳值過去一樣呵呵》。。。。。 舉這例子只為說明Tag在我的框架里除了作為配置之外。另外一個(gè)重要的用途就是‘界面?zhèn)鬟f值’ 呵呵。
D:我會(huì)根據(jù)ActField這個(gè)配置自動(dòng)的生成一個(gè)綁定器,當(dāng)然是雙向綁定。
6、怎么獲得‘表單’的值呢?
string data = JsonConvert.SerializeObject(_panel.DataContext);
這里的data就是我們要獲得的表單的所有的值,JsonConvert是一NewTonSoft里的一個(gè)類。SerializeObject是反序列化。_panel就是我們的那個(gè)表單。
呵呵,沒錯(cuò)。我們這樣就獲得了表單當(dāng)中的值。呵呵。
7、這樣弄有啥好處呢?
A: 加快了編程速度。傳統(tǒng)咱們要弄一個(gè)‘表單’啥的要前后折騰半天。而且那啥下拉列表框的級(jí)聯(lián)等等也要搞半天..... 在我這你只需要兩個(gè)配置即可。呵呵而且不只表單哦。。。。 列表,樹,ListBox......。都能用這個(gè)配置直接配置出來噢.....
B:讓代碼更加統(tǒng)一了。其實(shí)以前我們的開發(fā)。比較蛋疼的事情就是如果 十個(gè)人實(shí)現(xiàn)同一個(gè)功能,往往寫出來的代碼會(huì)有十個(gè)模樣(即便是團(tuán)隊(duì)有著非常詳細(xì)的編碼文檔,代碼也可能五花八門)。當(dāng)我們做代碼交接的時(shí)候往往要將代碼解釋半天。而用這樣的配置,則會(huì)讓代碼風(fēng)格非常統(tǒng)一。
C:牛逼的培訓(xùn)。呵呵,正式版本發(fā)布的時(shí)候,一定是伴隨這非常詳細(xì)的文檔,實(shí)例例子,甚至視頻教學(xué)噢。我想一個(gè)框架給力不給力其實(shí)很重要的一部分就是學(xué)習(xí)資料爽不爽。我想這一點(diǎn)因?yàn)楦绲拇嬖诓粫?huì)差 哈哈。
8、約定大于配置?
這話我想你聽過。。。。呵呵。編程大牛常常說這話。那么按照這個(gè)字面意思理解,是不是我的編程方式不如‘約定編程’呢。
錯(cuò)。呵呵,要知道這話你是不能只理解面的意思的。
約定大于配置本意就是要約束開發(fā)人員按照某約定的模式編程,盡量把更多的東西約定好統(tǒng)一好,而不是‘配置’(此配置非彼配置)。
那么我的這種編碼模式剛好符合這種理念。又或者我的編碼模式可以叫約定型編程。即約定了咱們就這么在Tag里寫那些來實(shí)現(xiàn)業(yè)務(wù)呵呵。
未完待續(xù)
呵呵,現(xiàn)在我的TagSL還在開發(fā)期,還有一些細(xì)節(jié)的一些東西需要優(yōu)化。我曾說過要在52天后放出一個(gè)開源版本。呵呵。我明年可能還會(huì)將工作流啥的集成進(jìn)來噢.... 哈哈。
誠然,我想我一定會(huì)遭到一部分兄弟的噴擊。畢竟我才入行一年,就居然說要做框架。怎么這么狂妄呵呵(一個(gè)哥們對(duì)我說的原話)...... 其實(shí)我只是想尋找更優(yōu)秀的軟件制作方式而已。唉....
噢,忘了說了,雖然我只編程了一年半,但要注意的是我的框架是站在居然的肩膀上... 呵呵。
為什么我會(huì)如此執(zhí)著的弄著一個(gè)‘框架’?為什么我一個(gè)才兩年不到編程的人敢于弄框架?為什么我對(duì)‘配置’如此..... 請(qǐng)看下集 《我在hangar學(xué)配置》
談的是在一個(gè)幾乎天天談配置的公司的學(xué)習(xí)經(jīng)歷。
這家公司有不懂編程語言的人憑配置做了兩年開發(fā)了.. 你信嗎??



浙公網(wǎng)安備 33010602011771號(hào)