最近在Academy做了一個練習TaskVision,用WPF+SQL Server 2008完成。主要的功能是,實現一個任務分配管理。具體如下:
系統登入,登入完成後,在MainWindow中用DataGrid顯示任務的資訊,可根據指定條件進行過濾;單擊列表,頁面下顯示詳細資訊;雙擊則可對該任務進行重新編輯;在Menu中點選新增,單獨顯示一頁進行任務新增。
下面就其中SQL Server及WPF涉及的,感覺有必要進一步說明的地方,列表如下:
- 1.MS SQL Server 2008 Management Studio-一個設定問題(知道就行)
- 2.sqlserver string to datetime,datetime to String問題(貌似Oracle沒有遇到這個問題!)
- 3.登入窗體完成後關閉登入窗體(和Winform不同,後面的博文有講到Winform實現);單例項執行WPF窗體---WPF應用程式生命週期
- 4.ComboBox和DataGrid Binding示例
- 5.獲取ComboBox和DataGrid選中項的值----通用的方法:根據Visual Tree取值!
- 6.WPF窗體間傳值---建構函式,Public類的public Static 欄位和建構函式(既然寫了就再提提)
- 7.從一個Form中重新整理(觸發)另一個Form的方法:更改或新增Task的Form完成後更新MainForm,這個還不同於前面DebugLZQ的另一篇博文:.NET一個執行緒更新另一個執行緒的UI(兩種實現方法)
看完以上目錄,如果你已經瞭然於胸,則可以繞行了。本身也只是個很小的一個Demo,沒什麼高階的東西。MainWindow如下:
下面對上面提及的幾點依次進行說明。
1.MS SQL Server 2008 Management Studio-一個設定問題(知道就行)
使用MS SQL Server 2008 Management Studio的圖形化介面對錶進行編輯的時候,譬如說增加一個欄位。當進行儲存後,提示:表需要re-creation,無法儲存。不合理啊!
解決方法如下:
在Tools-Options中進行如下取消"Prevent saving changes that require table re-creation"勾選。
這樣使用起來就方便多了。
2.sqlserver string to datetime,datetime to String問題(貌似Oracle沒有遇到這個問題!)
我為什麼抱怨這個,先來看Oracle如何做的
函式是不是很方便記憶,當然類似如此的格式化方式:“MM/DD/YYYY"怎麼會記不住呢?
下面來看下SQL Server如何搞的:
use TaskVision; SELECT convert(datetime, 'Oct 23 2012 11:01AM', 100) -- mon dd yyyy hh:mmAM (or PM) SELECT convert(datetime, 'Oct 23 2012 11:01AM') -- 2012-10-23 11:01:00.000 -- Without century (yy) string date conversion - convert string to datetime SELECT convert(datetime, 'Oct 23 12 11:01AM', 0) -- mon dd yy hh:mmAM (or PM) SELECT convert(datetime, 'Oct 23 12 11:01AM') -- 2012-10-23 11:01:00.000 -- Convert string to datetime sql - convert string to date sql - sql dates format -- T-SQL convert string to datetime - SQL Server convert string to date SELECT convert(datetime, '10/23/2016', 101) -- mm/dd/yyyy SELECT convert(datetime, '2016.10.23', 102) -- yyyy.mm.dd SELECT convert(datetime, '23/10/2016', 103) -- dd/mm/yyyy SELECT convert(datetime, '23.10.2016', 104) -- dd.mm.yyyy SELECT convert(datetime, '23-10-2016', 105) -- dd-mm-yyyy -- mon types are nondeterministic conversions, dependent on language setting SELECT convert(datetime, '23 OCT 2016', 106) -- dd mon yyyy SELECT convert(datetime, 'Oct 23, 2016', 107) -- mon dd, yyyy -- 2016-10-23 00:00:00.000 SELECT convert(datetime, '20:10:44', 108) -- hh:mm:ss -- 1900-01-01 20:10:44.000 -- mon dd yyyy hh:mm:ss:mmmAM (or PM) - sql time format SELECT convert(datetime, 'Oct 23 2016 11:02:44:013AM', 109) -- 2016-10-23 11:02:44.013 SELECT convert(datetime, '10-23-2016', 110) -- mm-dd-yyyy SELECT convert(datetime, '2016/10/23', 111) -- yyyy/mm/dd SELECT convert(datetime, '20161023', 112) -- yyyymmdd -- 2016-10-23 00:00:00.000 SELECT convert(datetime, '23 Oct 2016 11:02:07:577', 113) -- dd mon yyyy hh:mm:ss:mmm -- 2016-10-23 11:02:07.577 SELECT convert(datetime, '20:10:25:300', 114) -- hh:mm:ss:mmm(24h) -- 1900-01-01 20:10:25.300 SELECT convert(datetime, '2016-10-23 20:44:11', 120) -- yyyy-mm-dd hh:mm:ss(24h) -- 2016-10-23 20:44:11.000 SELECT convert(datetime, '2016-10-23 20:44:11.500', 121) -- yyyy-mm-dd hh:mm:ss.mmm -- 2016-10-23 20:44:11.500 SELECT convert(datetime, '2008-10-23T18:52:47.513', 126) -- yyyy-mm-ddThh:mm:ss.mmm -- 2008-10-23 18:52:47.513 -- Convert DDMMYYYY format to datetime SELECT convert(datetime, STUFF(STUFF('31012016',3,0,'-'),6,0,'-'), 105) -- 2016-01-31 00:00:00.000 -- SQL string to datetime conversion without century - some exceptions SELECT convert(datetime, '10/23/16', 1) -- mm/dd/yy SELECT convert(datetime, '16.10.23', 2) -- yy.mm.dd SELECT convert(datetime, '23/10/16', 3) -- dd/mm/yy SELECT convert(datetime, '23.10.16', 4) -- dd.mm.yy SELECT convert(datetime, '23-10-16', 5) -- dd-mm-yy SELECT convert(datetime, '23 OCT 16', 6) -- dd mon yy SELECT convert(datetime, 'Oct 23, 16', 7) -- mon dd, yy SELECT convert(datetime, '20:10:44', 8) -- hh:mm:ss SELECT convert(datetime, 'Oct 23 16 11:02:44:013AM', 9) SELECT convert(datetime, '10-23-16', 10) -- mm-dd-yy SELECT convert(datetime, '16/10/23', 11) -- yy/mm/dd SELECT convert(datetime, '161023', 12) -- yymmdd SELECT convert(datetime, '23 Oct 16 11:02:07:577', 13) -- dd mon yy hh:mm:ss:mmm SELECT convert(datetime, '20:10:25:300', 14) -- hh:mm:ss:mmm(24h) SELECT convert(datetime, '2016-10-23 20:44:11',20) -- yyyy-mm-dd hh:mm:ss(24h) SELECT convert(datetime, '2016-10-23 20:44:11.500', 21) -- yyyy-mm-dd hh:mm:ss.mmm
以上程式碼試過,可以正常轉換。
注意這個101和103搞了我好久!
3.登入窗體完成後關閉登入窗體,單例項執行WPF窗體---WPF應用程式生命週期
點選登入後顯示Main窗體,並關閉此登入窗體。Baidu了下,搜尋到了各種奇葩的答案。
正解如下:在WPF中Application的關閉模式同Winform確實不同,WPF中應用程式的關閉模式有三種,它由Application物件的ShutdownMode屬性來決定的。它的列舉值如下:
列舉名稱 |
列舉值 |
說明 |
OnLastWindowClose |
0 |
當應用程式最後一個視窗關閉後則整個應用結束 |
OnMainWindowClose |
1 |
當主視窗關閉後則應用程式結束 |
OnExplicitShutdown |
2 |
只用通過呼叫Application.Current.Shutdown()才能結束應用程式 |
從上表我們也可以看到預設情況下ShutdownMode值是OnLastWindowClose,因此當MainWindow關閉後應用程式沒有退出,如果要修改它可以將游標放到App.xaml中的XAML編輯視窗中,然後修改屬性視窗中的ShutdownMode,也可以在XAML中或者程式中設定ShutdownMode屬性。因此直接關閉就好!
WPF單例項執行窗體和Winform是一樣的,修改App.xaml.cs如下:
using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Linq; using System.Windows; using System.Threading; namespace TaskVision_V_1 { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : Application { //單例項執行程式 Mutex mutex = null; protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); bool createNew = false; mutex = new Mutex(true, "single", out createNew); if (!createNew) { MessageBox.Show("應用程式正在執行!"); Application.Current.Shutdown(); } } } }
4.ComboBox和DataGrid Binding示例
<Grid> <DataGrid SelectionMode="Single" SelectionUnit="FullRow" AlternatingRowBackground="LemonChiffon" AutoGenerateColumns="False" Margin="168,51,48,216" Name="dataGrid1" SelectionChanged="dataGrid1_SelectionChanged" MouseDoubleClick="dataGrid1_MouseDoubleClick"> <DataGrid.Columns> <DataGridTextColumn Header="Id" Width="20" Binding="{Binding Id}" IsReadOnly="True"/> <DataGridTextColumn Header="!" Width="20" Binding="{Binding PLevel}" Visibility="Hidden"/> <DataGridTemplateColumn Header="!" Width="20" IsReadOnly="True" > <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Image Source="{Binding Image}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTextColumn Header="分配給" Width="60" Binding="{Binding Distribution}" IsReadOnly="True"/> <DataGridTextColumn Header="摘要" Width="260" Binding="{Binding Abstract}" IsReadOnly="True"/> <DataGridTextColumn Header="狀態" Width="60" Binding="{Binding Status}" IsReadOnly="True"/> <!--<DataGridTextColumn Header="進度" Width="160" Binding="{Binding Rate}"/>--> <!----> <DataGridTemplateColumn Header="進度" SortMemberPath="Rate" Width="100" IsReadOnly="True"> <DataGridTemplateColumn.CellTemplate> <DataTemplate > <Grid> <Rectangle Height="20" MinWidth="0" MaxWidth="100" Fill="#FF9CB8F1" Width="{Binding Path=Rate}" VerticalAlignment="Center" HorizontalAlignment="Left" /> <StackPanel Orientation="Horizontal"> <TextBlock Height="20" Width="30" Text="{Binding Path=Rate}" TextAlignment="Right" /> <TextBlock Height="20" Width="30" Text="%" TextAlignment="Left"/> </StackPanel> </Grid> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTextColumn Foreground="Red" Header="截止日期" Width="140" Binding="{Binding Deadline}" IsReadOnly="True"/> <DataGridTextColumn Header="修改人" Width="30" Binding="{Binding Mender}" IsReadOnly="True" Visibility="Hidden"/> <DataGridTextColumn Header="詳細" Width="60" Binding="{Binding Detail}" IsReadOnly="True" Visibility="Hidden"/> </DataGrid.Columns> </DataGrid>
<ComboBox Height="23" HorizontalAlignment="Left" Margin="12,85,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" SelectionChanged="comboBox1_SelectionChanged"/>
//Binding DataGrid DataTable dataTable = SQLHelper.GetDataTable("select * from tb_TaskInfo"); dataGrid1.ItemsSource = dataTable.DefaultView;
//Binding ComboBox DataTable dataTable2 = SQLHelper.GetDataTable("select distinct TaskName from tb_TaskInfo"); comboBox1.ItemsSource = dataTable2.DefaultView; comboBox1.DisplayMemberPath = "TaskName";
SQLHelper類如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using System.Data.SqlClient; namespace TaskVision_V_1 { class SQLHelper { public const string connectionString = @"server=LocalHost;database=TaskVision;Trusted_Connection=SSPI"; public static DataTable GetDataTable(string sqlText) { using (SqlConnection conn = new SqlConnection(connectionString)) { SqlDataAdapter sda = new SqlDataAdapter(sqlText, conn); DataTable dt = new DataTable(); sda.Fill(dt); return dt; } } public static int ExecuteNonQuery(string sqlText) { using (SqlConnection conn = new SqlConnection(connectionString)) { SqlCommand cmd = new SqlCommand (sqlText, conn); conn.Open(); int temp = cmd.ExecuteNonQuery(); return temp; } } } }
其結果為前面的MainWindow所示。
5.獲取ComboBox和DataGrid選中項的值----通用的方法:根據Visual Tree取值!
獲取DataGrid選中行的值
//獲取DataGrid選中行值 DataRowView selectedItem = dataGrid1.SelectedItem as DataRowView; string PLevel = selectedItem["PLevel"].ToString();
獲取ComboBox選中行的值
如下ComboBox:
<ComboBox Height="23" HorizontalAlignment="Left" Margin="60,79,0,0" Name="cbBoxPLevel" VerticalAlignment="Top" Width="120" > <ComboBoxItem > <StackPanel Orientation="Horizontal" > <Image Width="19" Height="19" Source="/TaskVision_V_1;component/Images/Major.gif" /> <TextBlock Height="19" Text="Major"/> </StackPanel> </ComboBoxItem> <ComboBoxItem > <StackPanel Orientation="Horizontal" > <Image Width="19" Height="19" Source="/TaskVision_V_1;component/Images/Medium.gif" /> <TextBlock Height="19" Text="Medium"/> </StackPanel> </ComboBoxItem> <ComboBoxItem > <StackPanel Orientation="Horizontal" > <Image Width="19" Height="19" Source="/TaskVision_V_1;component/Images/Minor.gif" /> <TextBlock Height="19" Text="Minor"/> </StackPanel> </ComboBoxItem> </ComboBox>
//根據Visual Tree獲得指定的內容--典型代表 string New_PLevel = (((cbBoxPLevel.Items[cbBoxPLevel.SelectedIndex] as ComboBoxItem).Content as StackPanel).Children[1] as TextBlock).Text;
如下ComboBox,其值通過Bingding獲得。
<ComboBox Height="23" HorizontalAlignment="Left" Margin="251,6,0,0" Name="cbBoxDistribution" VerticalAlignment="Top" Width="120" />
string New_Distribution = (cbBoxDistribution.GetValue(ComboBox.SelectedValueProperty) as DataRowView).Row.ItemArray.GetValue(0).ToString();
下面這樣的最簡單
<ComboBox Height="23" HorizontalAlignment="Left" Margin="251,79,0,0" Name="cbBoxStatus" VerticalAlignment="Top" Width="120"> <ComboBoxItem Content="Open" /> <ComboBoxItem Content="Close" /> </ComboBox>
string New_Status = (cbBoxStatus.Items[cbBoxStatus.SelectedIndex] as ComboBoxItem).Content.ToString();
6.WPF窗體間傳值---建構函式,公共類的public Static 欄位和建構函式(既然寫了就再提提)
窗體間傳值,可以通過公共類的pubic static欄位。新增一個Globle.cs類。
using System; namespace TaskVision_V_1 { class Global { public static string userName = ""; } }
然後進行賦值取值。
也可以通過建構函式。就用這個例子來說,從MainForm中開啟TaskDetail,並把DataGrid選中行的Id傳過去。
過載TaskDetail的建構函式:
//建構函式傳值 private string id; public TaskDetail(string _id) { InitializeComponent(); id = _id; }
MainForm中呼叫該建構函式,如下:
private void dataGrid1_MouseDoubleClick(object sender, MouseButtonEventArgs e) { //獲取選中行值 DataRowView selectedItem = dataGrid1.SelectedItem as DataRowView; string Id = selectedItem["Id"].ToString(); //建構函式傳值 TaskDetail taskDetailForm = new TaskDetail(Id); taskDetailForm.Show(); }
7.從一個Form中重新整理另一個Form/一個Form觸發另一個Form中的方法:更改或新增Task的Form完成後更新MainForm,這個還不同於前面DebugLZQ的另一篇博文:.NET一個執行緒更新另一個執行緒的UI(兩種實現方法)
在MainForm中新增一個public static MainWindow,及相關的重新整理方法。如下:
public static MainWindow mainWindow = null; public MainWindow() { InitializeComponent(); mainWindow = this; } public void RefreshWindow() { //Binding DataGrid DataTable dataTable = SQLHelper.GetDataTable("select * from tb_TaskInfo"); dataGrid1.ItemsSource = dataTable.DefaultView; } public void RefreshWindow2() { Window_Loaded(this, null); }
在TaskDetail/TaskNew中使用的地方如下:
private void Window_Closed(object sender, EventArgs e) { //A窗體更新B窗體 MainWindow.mainWindow.RefreshWindow(); //MainWindow mainwindow = new MainWindow();//事實證明不行;不new,做一個public static的方法?怎麼訪問非static的控制元件 //mainwindow.RefreshWindow(); }
private void Window_Closed(object sender, EventArgs e) { MainWindow.mainWindow.RefreshWindow2(); }
文章介紹的內容沒有什麼可圈可點的東西,點滴積累,不喜勿噴~
後面應該會加入LINQ、Entity Framework、MVVM等框架重新實現之,請期待~