WPF+SQL Server 2008 TaskVision Demo小结

时间:2021-02-16 06:48:25

  最近在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如下:

WPF+SQL Server 2008 TaskVision Demo小结

下面对上面提及的几点依次进行说明。

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"勾选。

WPF+SQL Server 2008 TaskVision Demo小结

 这样使用起来就方便多了。

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如何搞的: 

WPF+SQL Server 2008 TaskVision Demo小结WPF+SQL Server 2008 TaskVision Demo小结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应用程序生命周期

 WPF+SQL Server 2008 TaskVision Demo小结

点击登录后显示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类如下:

WPF+SQL Server 2008 TaskVision Demo小结WPF+SQL Server 2008 TaskVision Demo小结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等框架重新实现之,请期待~