Visual Studio C# Properties.Settings.Default 问题
Visual Studio C# Properties.Settings.Default issues
我 运行 遇到的问题是我正在为 Excel 构建组合的 COM 和自动化插件。当尝试访问我创建的自动化加载项 class 中的 Properties.Settings.Default 时,通过的值是我为项目设置为默认值的值,即使 COM 加载项 returns 值已通过配置表单保存。
所有 class 都在同一个项目和同一个命名空间下,我的配置表单、COM 加载项和功能区的 class 文件都能够访问更新的 Properties.Settings.Default 值。我的自动化加载项和静态 class(处理所有繁重的工作)无法访问更新后的值。
COM 加载项:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Excel;
using System.Windows.Forms;
namespace DBLink
{
public partial class ThisAddIn
{
//public Dictionary<string, string> reports;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
MessageBox.Show("User ID = " + Properties.Settings.Default.DBUser + "; Password = " + Properties.Settings.Default.DBPassword + "; Data Source = " + Properties.Settings.Default.DBServer + "; Initial Catalog = " + Properties.Settings.Default.DBName + "; ");
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}
功能区:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;
using Microsoft.Office.Tools.Ribbon;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.Office.Tools.Excel;
namespace DBLink
{
public partial class Ribbon1
{
private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
{
//Even setting the connection string from a class that has
//access to the correct values fails and says the connection
//string is not initialised.
string conString;
conString = "User ID = " + Properties.Settings.Default.DBUser + "; Password = " + Properties.Settings.Default.DBPassword + "; Data Source = " + Properties.Settings.Default.DBServer + "; Initial Catalog = " + Properties.Settings.Default.DBName + "; ";
DataLink.connString = conString;
MessageBox.Show("User ID = " + Properties.Settings.Default.DBUser + "; Password = " + Properties.Settings.Default.DBPassword + "; Data Source = " + Properties.Settings.Default.DBServer + "; Initial Catalog = " + Properties.Settings.Default.DBName + "; ");
}
private void button1_Click(object sender, RibbonControlEventArgs e)
{
Form frm = new Form1();
frm.ShowDialog();
}
private void button2_Click(object sender, RibbonControlEventArgs e)
{
try
{
DataLink.LoadData(Globals.ThisAddIn.Application.ActiveWorkbook);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
private void button5_Click(object sender, RibbonControlEventArgs e)
{
//Do Stuff
}
private void button3_Click(object sender, RibbonControlEventArgs e)
{
//Do Stuff
}
}
}
形式:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Windows.Forms;
namespace DBLink
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
Properties.Settings.Default.DBServer = textBox1.Text;
Properties.Settings.Default.DBName = textBox2.Text;
Properties.Settings.Default.DBUser = textBox3.Text;
Properties.Settings.Default.DBPassword = textBox4.Text;
Properties.Settings.Default.Save();
}
private void button1_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection("User ID = " + Properties.Settings.Default.DBUser + "; Password = " + Properties.Settings.Default.DBPassword + "; Data Source = " + Properties.Settings.Default.DBServer + "; Initial Catalog = " + Properties.Settings.Default.DBName + "; ");
try
{
con.Open();
MessageBox.Show("Connected successfully");
con.Close();
}
catch
{
MessageBox.Show("There was a problem connecting to the database. Please confirm the details!");
}
}
}
}
自动化:
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace DBLink
{
[Guid("19C7ACDB-1572-4988-984F-3C56AEF117A5")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public partial class MyFunctions2
{
string connectionString;
public MyFunctions2()
{
}
private static string GetSubKeyName(Type type, string subKeyName)
{
System.Text.StringBuilder s = new System.Text.StringBuilder();
s.Append(@"CLSID\{");
s.Append(type.GUID.ToString().ToUpper());
s.Append(@"}\");
s.Append(subKeyName);
return s.ToString();
}
public string MTD(int year, int period, string costCentre, string account)
{
connectionString = "User ID = " + Properties.Settings.Default.DBUser + "; Password = " + Properties.Settings.Default.DBPassword + "; Data Source = " + Properties.Settings.Default.DBServer + "; Initial Catalog = " + Properties.Settings.Default.DBName + "; ";
return DataLink.MTD(year, period, costCentre, account, connectionString).ToString();
}
public double MultiplyNTimes2(double number1, double number2, double timesToMultiply)
{
return DataLink.MultiplyNTimes(number1, number2, timesToMultiply);
}
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{
Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type, "Programmable"));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(GetSubKeyName(type, "InprocServer32"), true);
key.SetValue("", System.Environment.SystemDirectory + @"\mscoree.dll", RegistryValueKind.String);
}
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
{
Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type, "Programmable"), false);
}
}
}
最后静态class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;
using Microsoft.Office.Tools.Ribbon;
using Excel = Microsoft.Office.Interop.Excel;
namespace DBLink
{
public static partial class DataLink
{
private static string commandText = "select case when ACClass in (2,3,4,5) then SUM(ISNULL(POCredit,0)-ISNULL(PODebit,0)) else SUM(ISNULL(PODebit,0)-ISNULL(POCredit,0)) end as value from Account join Post on ACID = POAccountID left join Segment on SID = POSegmentID join Journal on POJournalID = JID where DatePart(month,JDate) = @month and DatePart(year,JDate) = @year and ACCode = @account and (SName = @seg or @seg = '*') group by ACClass";
public static string connString="";
private static SqlConnection con;
public static void SetConnString(string connection)
{
connString = connection;
}
public static void LoadData(Excel.Workbook wb)
{
//Do stuff... may be deprecated before release.
}
public static double MTD(int year, int period, string costCentre, string account, string conString)
{
DataTable dt = new DataTable();
DataSet ds = new DataSet();
double result = 0;
int month = period > 6 ? period - 6 : period + 6;
int actualYear = month > 6 ? year - 1 : year;
MessageBox.Show("User ID = " + Properties.Settings.Default.DBUser + "; Password = " + Properties.Settings.Default.DBPassword + "; Data Source = " + Properties.Settings.Default.DBServer + "; Initial Catalog = " + Properties.Settings.Default.DBName + "; ");
con = new SqlConnection(connString);
try
{
using (SqlCommand cmd = new SqlCommand(commandText, con))
{
cmd.Parameters.AddWithValue("@month", month);
cmd.Parameters.AddWithValue("@year", actualYear);
cmd.Parameters.AddWithValue("@account", account);
cmd.Parameters.AddWithValue("@seg", costCentre);
MessageBox.Show(cmd.CommandText);
MessageBox.Show(cmd.Connection.ConnectionString);
cmd.Connection.Open();
dt.Load(cmd.ExecuteReader());
if (dt.Rows.Count > 0)
{
MessageBox.Show("We have a row");
ds.Tables.Add(dt);
result = double.Parse(ds.Tables[0].Rows[0].ItemArray[0].ToString());
}
cmd.Connection.Close();
MessageBox.Show(result.ToString());
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
return result;
}
}
}
我能想到的是,以某种方式创建了 2 个或更多设置实例。如果有人对如何解决这个问题有任何想法,那就太好了。
编辑: 多玩一点,似乎 COM 加载项在加载时只能看到保存的值,然后才能看到原始值。 Ribbon全程可以看到设置。
编辑 2: 已经计算出来并将答案放入以供将来参考,一旦 2 天限制结束将标记为答案。
好的,所以我找到了一个解决方案,因为所有内容都加载到不同的 AppDomains 中。
第一步:在ThisAddIn_Startup方法中调用this.Application.Evaluate("=MTD()");
。这意味着我的 COM 和自动化加载项都 运行 在同一个 AppDomain 下。
第 2 步:在 ThisAddIn_Startup 方法中将连接字符串传递到我的 DataLink class。
我 运行 遇到的问题是我正在为 Excel 构建组合的 COM 和自动化插件。当尝试访问我创建的自动化加载项 class 中的 Properties.Settings.Default 时,通过的值是我为项目设置为默认值的值,即使 COM 加载项 returns 值已通过配置表单保存。
所有 class 都在同一个项目和同一个命名空间下,我的配置表单、COM 加载项和功能区的 class 文件都能够访问更新的 Properties.Settings.Default 值。我的自动化加载项和静态 class(处理所有繁重的工作)无法访问更新后的值。
COM 加载项:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Excel;
using System.Windows.Forms;
namespace DBLink
{
public partial class ThisAddIn
{
//public Dictionary<string, string> reports;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
MessageBox.Show("User ID = " + Properties.Settings.Default.DBUser + "; Password = " + Properties.Settings.Default.DBPassword + "; Data Source = " + Properties.Settings.Default.DBServer + "; Initial Catalog = " + Properties.Settings.Default.DBName + "; ");
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}
功能区:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;
using Microsoft.Office.Tools.Ribbon;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.Office.Tools.Excel;
namespace DBLink
{
public partial class Ribbon1
{
private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
{
//Even setting the connection string from a class that has
//access to the correct values fails and says the connection
//string is not initialised.
string conString;
conString = "User ID = " + Properties.Settings.Default.DBUser + "; Password = " + Properties.Settings.Default.DBPassword + "; Data Source = " + Properties.Settings.Default.DBServer + "; Initial Catalog = " + Properties.Settings.Default.DBName + "; ";
DataLink.connString = conString;
MessageBox.Show("User ID = " + Properties.Settings.Default.DBUser + "; Password = " + Properties.Settings.Default.DBPassword + "; Data Source = " + Properties.Settings.Default.DBServer + "; Initial Catalog = " + Properties.Settings.Default.DBName + "; ");
}
private void button1_Click(object sender, RibbonControlEventArgs e)
{
Form frm = new Form1();
frm.ShowDialog();
}
private void button2_Click(object sender, RibbonControlEventArgs e)
{
try
{
DataLink.LoadData(Globals.ThisAddIn.Application.ActiveWorkbook);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
private void button5_Click(object sender, RibbonControlEventArgs e)
{
//Do Stuff
}
private void button3_Click(object sender, RibbonControlEventArgs e)
{
//Do Stuff
}
}
}
形式:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Windows.Forms;
namespace DBLink
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
Properties.Settings.Default.DBServer = textBox1.Text;
Properties.Settings.Default.DBName = textBox2.Text;
Properties.Settings.Default.DBUser = textBox3.Text;
Properties.Settings.Default.DBPassword = textBox4.Text;
Properties.Settings.Default.Save();
}
private void button1_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection("User ID = " + Properties.Settings.Default.DBUser + "; Password = " + Properties.Settings.Default.DBPassword + "; Data Source = " + Properties.Settings.Default.DBServer + "; Initial Catalog = " + Properties.Settings.Default.DBName + "; ");
try
{
con.Open();
MessageBox.Show("Connected successfully");
con.Close();
}
catch
{
MessageBox.Show("There was a problem connecting to the database. Please confirm the details!");
}
}
}
}
自动化:
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace DBLink
{
[Guid("19C7ACDB-1572-4988-984F-3C56AEF117A5")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public partial class MyFunctions2
{
string connectionString;
public MyFunctions2()
{
}
private static string GetSubKeyName(Type type, string subKeyName)
{
System.Text.StringBuilder s = new System.Text.StringBuilder();
s.Append(@"CLSID\{");
s.Append(type.GUID.ToString().ToUpper());
s.Append(@"}\");
s.Append(subKeyName);
return s.ToString();
}
public string MTD(int year, int period, string costCentre, string account)
{
connectionString = "User ID = " + Properties.Settings.Default.DBUser + "; Password = " + Properties.Settings.Default.DBPassword + "; Data Source = " + Properties.Settings.Default.DBServer + "; Initial Catalog = " + Properties.Settings.Default.DBName + "; ";
return DataLink.MTD(year, period, costCentre, account, connectionString).ToString();
}
public double MultiplyNTimes2(double number1, double number2, double timesToMultiply)
{
return DataLink.MultiplyNTimes(number1, number2, timesToMultiply);
}
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{
Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type, "Programmable"));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(GetSubKeyName(type, "InprocServer32"), true);
key.SetValue("", System.Environment.SystemDirectory + @"\mscoree.dll", RegistryValueKind.String);
}
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
{
Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type, "Programmable"), false);
}
}
}
最后静态class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;
using Microsoft.Office.Tools.Ribbon;
using Excel = Microsoft.Office.Interop.Excel;
namespace DBLink
{
public static partial class DataLink
{
private static string commandText = "select case when ACClass in (2,3,4,5) then SUM(ISNULL(POCredit,0)-ISNULL(PODebit,0)) else SUM(ISNULL(PODebit,0)-ISNULL(POCredit,0)) end as value from Account join Post on ACID = POAccountID left join Segment on SID = POSegmentID join Journal on POJournalID = JID where DatePart(month,JDate) = @month and DatePart(year,JDate) = @year and ACCode = @account and (SName = @seg or @seg = '*') group by ACClass";
public static string connString="";
private static SqlConnection con;
public static void SetConnString(string connection)
{
connString = connection;
}
public static void LoadData(Excel.Workbook wb)
{
//Do stuff... may be deprecated before release.
}
public static double MTD(int year, int period, string costCentre, string account, string conString)
{
DataTable dt = new DataTable();
DataSet ds = new DataSet();
double result = 0;
int month = period > 6 ? period - 6 : period + 6;
int actualYear = month > 6 ? year - 1 : year;
MessageBox.Show("User ID = " + Properties.Settings.Default.DBUser + "; Password = " + Properties.Settings.Default.DBPassword + "; Data Source = " + Properties.Settings.Default.DBServer + "; Initial Catalog = " + Properties.Settings.Default.DBName + "; ");
con = new SqlConnection(connString);
try
{
using (SqlCommand cmd = new SqlCommand(commandText, con))
{
cmd.Parameters.AddWithValue("@month", month);
cmd.Parameters.AddWithValue("@year", actualYear);
cmd.Parameters.AddWithValue("@account", account);
cmd.Parameters.AddWithValue("@seg", costCentre);
MessageBox.Show(cmd.CommandText);
MessageBox.Show(cmd.Connection.ConnectionString);
cmd.Connection.Open();
dt.Load(cmd.ExecuteReader());
if (dt.Rows.Count > 0)
{
MessageBox.Show("We have a row");
ds.Tables.Add(dt);
result = double.Parse(ds.Tables[0].Rows[0].ItemArray[0].ToString());
}
cmd.Connection.Close();
MessageBox.Show(result.ToString());
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
return result;
}
}
}
我能想到的是,以某种方式创建了 2 个或更多设置实例。如果有人对如何解决这个问题有任何想法,那就太好了。
编辑: 多玩一点,似乎 COM 加载项在加载时只能看到保存的值,然后才能看到原始值。 Ribbon全程可以看到设置。
编辑 2: 已经计算出来并将答案放入以供将来参考,一旦 2 天限制结束将标记为答案。
好的,所以我找到了一个解决方案,因为所有内容都加载到不同的 AppDomains 中。
第一步:在ThisAddIn_Startup方法中调用this.Application.Evaluate("=MTD()");
。这意味着我的 COM 和自动化加载项都 运行 在同一个 AppDomain 下。
第 2 步:在 ThisAddIn_Startup 方法中将连接字符串传递到我的 DataLink class。