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

  • 相关阅读:
    linux删除/var/log/下面所有日志 如何重新记录日志
    DIV里的内容自动换行
    it冲突:commit your changes or stash them before you can merge. 解决办法
    git切换到远程分支
    【异常】warning: refname 'feature1.3.0' is ambiguous.导致git merge失败
    在此篇文章中,我们将用 15 分钟对 PHP v7.x 版本更改进行简要回顾
    input元素所有type类型及相关作用
    微信自动关闭内置浏览器页面,返回公众号窗口 WeixinJSBridge.call('closeWindow')
    css背景渐变色
    数组的forEach和map和for方法的区别
  • 原文地址:https://www.cnblogs.com/DebugLZQ/p/3016091.html
Copyright © 2020-2023  润新知