zoukankan      html  css  js  c++  java
  • WPF+SQL Server 2008 TaskVision Demo小结

      最近在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如何做的

    TO_DATE
    Convert A String With Default Format To A Date TO_DATE(<string>) RETURN DATE
    SELECT TO_DATE('01-JAN-2004') FROM dual;
    Convert A String With A Non-Default Format To A Date TO_DATE(<string>, <format mask>)
    SELECT TO_DATE('01/01/2004', 'MM/DD/YYYY') FROM dual;
    Convert A String With A Non-Default Format And Specify The Language TO_DATE(<string>, <format mask>) RETURN DATE
    SELECT TO_DATE('January 12, 2005, 11:03 A.M.', 'MONTH DD, YYYY, HH:MI A.M.', 'NLS_DATE_LANGUAGE = American') FROM dual;
    Convert A String With A Non-Default Format And Specify The Language TO_DATE(<date_string>, <format mask>, <NLS_PARAMETER>) RETURN DATE
    ALTER SESSION SET NLS_TERRITORY = 'JAPAN';
    SELECT TO_DATE('January 12, 2005, 11:03 A.M.', 'Month dd, YYYY, HH:MI A.M.', 'NLS_DATE_LANGUAGE = American') FROM DUAL;
    ALTER SESSION SET NLS_TERRITORY = 'AMERICA';
    Convert A String To 24 Hour Time TO_DATE(<date_string>, <format mask>) RETURN DATE
    SELECT TO_CHAR(SYSDATE, 'MM/DD/YY HH24:MI:SS') FROM dual;

    函数是不是很方便记忆,当然类似如此的格式化方式:“MM/DD/YYYY"怎么会记不住呢?

    下面来看下SQL Server如何搞的: 

    View Code
    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类如下:

    View Code
    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等框架重新实现之,请期待~

  • 相关阅读:
    JVM 综述
    看 Netty 在 Dubbo 中如何应用
    Netty 心跳服务之 IdleStateHandler 源码分析
    Netty 高性能之道
    Netty 解码器抽象父类 ByteToMessageDecoder 源码解析
    Netty 源码剖析之 unSafe.write 方法
    Netty 出站缓冲区 ChannelOutboundBuffer 源码解析(isWritable 属性的重要性)
    Netty 源码剖析之 unSafe.read 方法
    Netty 内存回收之 noCleaner 策略
    Netty 源码阅读的思考------耗时业务到底该如何处理
  • 原文地址:https://www.cnblogs.com/DebugLZQ/p/3016091.html
Copyright © 2011-2022 走看看