本文整理汇总了C#中Microsoft.Tools.WindowsInstallerXml.Msi.Database类的典型用法代码示例。如果您正苦于以下问题:C# Database类的具体用法?C# Database怎么用?C# Database使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。
Database类属于Microsoft.Tools.WindowsInstallerXml.Msi命名空间,在下文中一共展示了Database类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。
示例1: GetPropertiesFromDatabase
internal static MsiPropertyInfo[] GetPropertiesFromDatabase(Database msidb)
{
int[] standardIDs = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 18, 19};
ArrayList properties = new ArrayList();
using (SummaryInformation summaryInfo = new SummaryInformation(msidb))
{
foreach (int propID in standardIDs)
{
bool failed = false;
object propValue = null;
try
{
propValue = summaryInfo.GetProperty(propID);
}
catch
{
failed = true;
}
if (!failed)
properties.Add(new MsiPropertyInfo(propID, propValue));
}
}
return (MsiPropertyInfo[]) properties.ToArray(typeof (MsiPropertyInfo));
}
示例2: GetRowsFromTable
public static TableRow[] GetRowsFromTable(Database msidb, string tableName)
{
if (!msidb.TableExists(tableName))
{
Trace.WriteLine(string.Format("Table name does {0} not exist Found.", tableName));
return new TableRow[0];
}
string query = string.Concat("SELECT * FROM `", tableName, "`");
using (var view = new ViewWrapper(msidb.OpenExecuteView(query)))
{
var /*<TableRow>*/ rows = new ArrayList(view.Records.Count);
ColumnInfo[] columns = view.Columns;
foreach (object[] values in view.Records)
{
HybridDictionary valueCollection = new HybridDictionary(values.Length);
for (int cIndex = 0; cIndex < columns.Length; cIndex++)
{
valueCollection[columns[cIndex].Name] = values[cIndex];
}
rows.Add(new TableRow(valueCollection));
}
return (TableRow[]) rows.ToArray(typeof(TableRow));
}
}
示例3: CreateMsiFilesFromMSI
/// <summary>
/// Creates a list of <see cref="MsiFile"/> objects from the specified database.
/// </summary>
public static MsiFile[] CreateMsiFilesFromMSI(string msiDatabaseFilePath)
{
using (var db = new Database(msiDatabaseFilePath, OpenDatabase.ReadOnly))
{
return CreateMsiFilesFromMSI(db);
}
}
示例4: Run
public override void Run(List<string> args)
{
// args[0]=v, args[1]=filename.msi
if (args.Count < 2)
throw new OptionException("You must specify an msi filename.", "v");
var msiFileName = args[1];
using (var msidb = new Database(msiFileName, OpenDatabase.ReadOnly))
{
const string tableName = "Property";
var query = string.Format(CultureInfo.InvariantCulture, "SELECT * FROM `{0}`", tableName);
using (var view = new ViewWrapper(msidb.OpenExecuteView(query)))
{
foreach (var row in view.Records)
{
var property = (string)row[view.ColumnIndex("Property")];
var value = row[view.ColumnIndex("Value")];
if (string.Equals("ProductVersion", property, StringComparison.InvariantCultureIgnoreCase))
{
Console.WriteLine(value);
return;
}
}
Console.WriteLine("Version not found!");
}
}
}
示例5: Run
public override void Run(List<string> args)
{
/* examples:
* lessmsi l -t Component c:\theinstall.msi
* lessmsi l -t Property c:\theinstall.msi
*/
args = args.Skip(1).ToList();
var tableName = "";
var options = new OptionSet {
{ "t=", "Specifies the table to list.", t => tableName = t }
};
var extra = options.Parse(args);
if (extra.Count < 1)
throw new OptionException("You must specify the msi file to list from.", "l");
if (string.IsNullOrEmpty(tableName))
throw new OptionException("You must specify the table name to list.", "t");
var csv = new StringBuilder();
Debug.Print("Opening msi file '{0}'.", extra[0]);
using (var msidb = new Database(extra[0], OpenDatabase.ReadOnly))
{
Debug.Print("Opening table '{0}'.", tableName);
var query = string.Format(CultureInfo.InvariantCulture, "SELECT * FROM `{0}`", tableName);
using (var view = new ViewWrapper(msidb.OpenExecuteView(query)))
{
for (var index = 0; index < view.Columns.Length; index++)
{
var col = view.Columns[index];
if (index > 0)
csv.Append(',');
csv.Append(col.Name);
}
csv.AppendLine();
foreach (var row in view.Records)
{
for (var colIndex = 0; colIndex < row.Length; colIndex++)
{
if (colIndex > 0)
csv.Append(',');
var val = Convert.ToString(row[colIndex], CultureInfo.InvariantCulture);
var newLine = Environment.NewLine;
string[] requireEscapeChars = { ",", newLine };
Array.ForEach(requireEscapeChars, s => {
if (val.Contains(s))
val = "\"" + val + "\"";
});
csv.Append(val);
}
csv.AppendLine();
}
}
}
Console.Write(csv.ToString());
}
示例6: Session
/// <summary>
/// Instantiate a new Session.
/// </summary>
/// <param name="database">The database to open.</param>
public Session(Database database)
{
string packagePath = String.Format(CultureInfo.InvariantCulture, "#{0}", (uint)database.Handle);
uint handle = 0;
int error = MsiInterop.MsiOpenPackage(packagePath, out handle);
if (0 != error)
{
throw new MsiException(error);
}
this.Handle = handle;
}
示例7: SummaryInformation
/// <summary>
/// Instantiate a new SummaryInformation class from the database.
/// </summary>
/// <param name="db">Database to retrieve summary information from.</param>
public SummaryInformation(Database db)
{
if (null == db)
{
throw new ArgumentNullException("db");
}
uint error = MsiInterop.MsiGetSummaryInformation(db.InternalHandle, null, 20, ref handle);
if (0 != error)
{
throw new ArgumentNullException(); // TODO: come up with a real exception to throw
}
}
示例8: ExtractCabFromPackage
/// <summary>
/// Write the Cab to disk.
/// </summary>
/// <param name="filePath">Specifies the path to the file to contain the stream.</param>
/// <param name="cabName">Specifies the name of the file in the stream.</param>
public static void ExtractCabFromPackage(string filePath, string cabName, Database inputDatabase)
{
using (View view = inputDatabase.OpenExecuteView(String.Concat("SELECT * FROM `_Streams` WHERE `Name` = '", cabName, "'")))
{
Record record;
if (view.Fetch(out record))
{
FileStream cabFilestream = null;
BinaryWriter writer = null;
try
{
cabFilestream = new FileStream(filePath, FileMode.Create);
// Create the writer for data.
writer = new BinaryWriter(cabFilestream);
var buf = new byte[1024*1024];
int count;
do
{
const int MsiInterop_Storages_Data = 2; //From wiX:Index to column name Data into Record for row in Msi Table Storages
count = record.GetStream(MsiInterop_Storages_Data, buf, buf.Length);
if (count > 0)
writer.Write(buf, 0, count);
} while (count > 0);
}
finally
{
if (writer != null)
{
writer.Close();
}
if (cabFilestream != null)
{
cabFilestream.Close();
}
}
}
}
}
示例9: CabsFromMsiToDisk
/// <summary>
/// Extracts cab files from the specified MSIDB and puts them in the specified outputdir.
/// </summary>
/// <param name="msidb"></param>
/// <param name="outputDir"></param>
/// <returns></returns>
private static List<CabInfo> CabsFromMsiToDisk(Database msidb, DirectoryInfo outputDir)
{
const string query = "SELECT * FROM `Media`";
var localCabFiles = new List<CabInfo>();
using (View view = msidb.OpenExecuteView(query))
{
Record record;
while (view.Fetch(out record))
{
const int MsiInterop_Media_Cabinet = 4;
string cabSourceName = record[MsiInterop_Media_Cabinet];
if (string.IsNullOrEmpty(cabSourceName))
throw new IOException("Couldn't find media CAB file inside the MSI (bad media table?).");
if (!string.IsNullOrEmpty(cabSourceName))
{
if (cabSourceName.StartsWith("#"))
{
cabSourceName = cabSourceName.Substring(1);
// extract cabinet, then explode all of the files to a temp directory
string localCabFile = Path.Combine(outputDir.FullName, cabSourceName);
ExtractCabFromPackage(localCabFile, cabSourceName, msidb);
/* http://code.google.com/p/lessmsi/issues/detail?id=1
* apparently in some cases a file spans multiple CABs (VBRuntime.msi) so due to that we have get all CAB files out of the MSI and then begin extraction. Then after we extract everything out of all CAbs we need to release the CAB extractors and delete temp files.
* Thanks to Christopher Hamburg for explaining this!
*/
var c = new CabInfo(localCabFile, cabSourceName);
localCabFiles.Add(c);
}
}
}
}
return localCabFiles;
}
示例10: CreateTransformSummaryInfo
/// <summary>
/// Creates and populates the summary information stream of an existing transform file.
/// </summary>
/// <param name="referenceDatabase">Required database that does not include the changes.</param>
/// <param name="transformFile">The name of the generated transform file.</param>
/// <param name="errorConditions">Required error conditions that should be suppressed when the transform is applied.</param>
/// <param name="validations">Required when the transform is applied to a database;
/// shows which properties should be validated to verify that this transform can be applied to the database.</param>
public void CreateTransformSummaryInfo(Database referenceDatabase, string transformFile, TransformErrorConditions errorConditions, TransformValidations validations)
{
int error = MsiInterop.MsiCreateTransformSummaryInfo(this.Handle, referenceDatabase.Handle, transformFile, errorConditions, validations);
if (0 != error)
{
throw new MsiException(error);
}
}
示例11: GetMsiDirectories
/// <summary>
/// Creates a list of <see cref="MsiDirectory"/> objects from the specified database.
/// </summary>
/// <param name="allDirectories">All directories in the table.</param>
/// <param name="msidb">The databse to get directories from.</param>
/// <param name="rootDirectories">
/// Only the root directories (those with no parent). Use <see cref="MsiDirectory.Children"/> to traverse the rest of the directories.
/// </param>
public static void GetMsiDirectories(Database msidb, out MsiDirectory[] rootDirectories, out MsiDirectory[] allDirectories)
{
TableRow[] rows = TableRow.GetRowsFromTable(msidb, "Directory");
Hashtable directoriesByDirID = new Hashtable();
foreach (TableRow row in rows)
{
MsiDirectory directory = new MsiDirectory();
directory._defaultDir = row.GetString("DefaultDir");
if (directory._defaultDir != null && directory._defaultDir.Length > 0)
{
string[] split = directory._defaultDir.Split('|');
directory._shortName = split[0];
if (split.Length > 1)
directory._targetName = split[1];
else
directory._targetName = split[0];
//Semi colons can delmit the "target" and "sorce" names of the directory in DefaultDir, so we're going to use the Target here (in looking at MSI files, I found Target seems most meaningful.
#region MSDN Docs on this Table
/* From: http://msdn.microsoft.com/en-us/library/aa368295%28VS.85%29.aspx
The DefaultDir column contains the directory's name (localizable)under the parent directory.
By default, this is the name of both the target and source directories.
To specify different source and target directory names, separate the target and source names with a colon as follows: [targetname]:[sourcename].
If the value of the Directory_Parent column is null or is equal to the Directory column, the DefaultDir column specifies the name of a root source directory.
For a non-root source directory, a period (.) entered in the DefaultDir column for the source directory name or the target directory name indicates the directory should be located in its parent directory without a subdirectory.
The directory names in this column may be formatted as short filename | long filename pairs.
*/
#endregion
split = directory._shortName.Split(':');
if (split.Length > 1)
{ //semicolon present
directory._shortName = split[0];
}
split = directory._targetName.Split(':');
if (split.Length > 1)
{ //semicolon present
directory._targetName = split[0];
directory._sourceName = split[1];
}
else
{
directory._sourceName = directory._targetName;
}
}
directory._directory = row.GetString("Directory");
directory._directoryParent = row.GetString("Directory_Parent");
directoriesByDirID.Add(directory.Directory, directory);
}
//Now we have all directories in the table, create a structure for them based on their parents.
ArrayList rootDirectoriesList = new ArrayList();
foreach (MsiDirectory dir in directoriesByDirID.Values)
{
if (dir.DirectoryParent == null || dir.DirectoryParent.Length == 0)
{
rootDirectoriesList.Add(dir);
continue;
}
MsiDirectory parent = directoriesByDirID[dir.DirectoryParent] as MsiDirectory;
dir._parent = parent;
parent._children.Add(dir);
}
// return the values:
rootDirectories = (MsiDirectory[])rootDirectoriesList.ToArray(typeof(MsiDirectory));
MsiDirectory[] allDirectoriesLocal = new MsiDirectory[directoriesByDirID.Values.Count];
directoriesByDirID.Values.CopyTo(allDirectoriesLocal,0);
allDirectories = allDirectoriesLocal;
}
示例12: ExtractFiles
/// <summary>
/// Extracts the compressed files from the specified MSI file to the specified output directory.
/// If specified, the list of <paramref name="filesToExtract"/> objects are the only files extracted.
/// </summary>
/// <param name="filesToExtract">The files to extract or null or empty to extract all files.</param>
/// <param name="progressCallback">Will be called during during the operation with progress information, and upon completion. The argument will be of type <see cref="ExtractionProgress"/>.</param>
public static void ExtractFiles(FileInfo msi, DirectoryInfo outputDir, MsiFile[] filesToExtract, AsyncCallback progressCallback)
{
if (msi == null)
throw new ArgumentNullException("msi");
if (outputDir == null)
throw new ArgumentNullException("outputDir");
int filesExtractedSoFar = 0;
ExtractionProgress progress = null;
Database msidb = new Database(msi.FullName, OpenDatabase.ReadOnly);
try
{
if (filesToExtract == null || filesToExtract.Length < 1)
filesToExtract = MsiFile.CreateMsiFilesFromMSI(msidb);
progress = new ExtractionProgress(progressCallback, filesToExtract.Length);
if (!msi.Exists)
{
Trace.WriteLine("File \'" + msi.FullName + "\' not found.");
progress.ReportProgress(ExtractionActivity.Complete, "", filesExtractedSoFar);
return;
}
progress.ReportProgress(ExtractionActivity.Initializing, "", filesExtractedSoFar);
outputDir.Create();
//map short file names to the msi file entry
var fileEntryMap = new Dictionary<string, MsiFile>(filesToExtract.Length, StringComparer.InvariantCulture);
foreach (var fileEntry in filesToExtract)
{
MsiFile existingFile = null;
if (fileEntryMap.TryGetValue(fileEntry.File, out existingFile))
{ //NOTE: This used to be triggered when we ignored case of file, but now we don't ignore case so this is unlikely to occur.
// Differing only by case is not compliant with the msi specification but some installers do it (e.g. python, see issue 28).
Debug.Print("!!Found duplicate file using key {0}. The existing key was {1}", fileEntry.File, existingFile.File);
}
else
{
fileEntryMap.Add(fileEntry.File, fileEntry);
}
}
Debug.Assert(fileEntryMap.Count == filesToExtract.Length, "Duplicate files must have caused some files to not be in the map.");
var cabInfos = CabsFromMsiToDisk(msidb, outputDir);
var cabDecompressors = MergeCabs(cabInfos);
try
{
foreach (MSCabinet decompressor in cabDecompressors)
{
foreach (var compressedFile in decompressor.GetFiles())
{
// if the user didn't select this in the UI for extraction, skip it.
if (!fileEntryMap.ContainsKey(compressedFile.Filename))
continue;
var entry = fileEntryMap[compressedFile.Filename];
progress.ReportProgress(ExtractionActivity.ExtractingFile, entry.LongFileName, filesExtractedSoFar);
DirectoryInfo targetDirectoryForFile = GetTargetDirectory(outputDir, entry.Directory);
string destName = Path.Combine(targetDirectoryForFile.FullName, entry.LongFileName);
if (File.Exists(destName))
{
Debug.Fail("output file already exists. We'll make it unique, but this is probably a strange msi or a bug in this program.");
//make unique
// ReSharper disable HeuristicUnreachableCode
Trace.WriteLine(string.Concat("Duplicate file found \'", destName, "\'"));
int duplicateCount = 0;
string uniqueName;
do
{
uniqueName = string.Concat(destName, ".", "duplicate", ++duplicateCount);
} while (File.Exists(uniqueName));
destName = uniqueName;
// ReSharper restore HeuristicUnreachableCode
}
Trace.WriteLine(string.Concat("Extracting File \'", compressedFile.Filename, "\' to \'", destName, "\'"));
compressedFile.ExtractTo(destName);
filesExtractedSoFar++;
}
}
}
finally
{ //cleanup the decompressors allocated in MergeCabs
foreach (MSCabinet decomp in cabDecompressors)
{
decomp.Close(false);
File.Delete(decomp.LocalFilePath);
}
}
}
finally
{
if (msidb != null)
//.........这里部分代码省略.........
示例13: RunUnitTest
/// <summary>
/// Run a Torch unit test.
/// </summary>
/// <param name="element">The unit test element.</param>
/// <param name="previousUnitResults">The previous unit test results.</param>
/// <param name="update">Indicates whether to give the user the option to fix a failing test.</param>
/// <param name="args">The command arguments passed to WixUnit.</param>
public static void RunUnitTest(XmlElement element, UnitResults previousUnitResults, bool update, ICommandArgs args)
{
string arguments = element.GetAttribute("Arguments");
string expectedErrors = element.GetAttribute("ExpectedErrors");
string expectedWarnings = element.GetAttribute("ExpectedWarnings");
string extensions = element.GetAttribute("Extensions");
string outputFile = element.GetAttribute("OutputFile");
string targetDatabase = element.GetAttribute("TargetDatabase");
string tempDirectory = element.GetAttribute("TempDirectory");
string testName = element.ParentNode.Attributes["Name"].Value;
string toolsDirectory = element.GetAttribute("ToolsDirectory");
string updatedDatabase = element.GetAttribute("UpdatedDatabase");
bool usePreviousOutput = ("true" == element.GetAttribute("UsePreviousOutput"));
bool verifyTransform = ("true" == element.GetAttribute("VerifyTransform"));
string toolFile = Path.Combine(toolsDirectory, "torch.exe");
StringBuilder commandLine = new StringBuilder(arguments);
// handle extensions
if (!String.IsNullOrEmpty(extensions))
{
foreach (string extension in extensions.Split(';'))
{
commandLine.AppendFormat(" -ext \"{0}\"", extension);
}
}
// handle wixunit arguments
if (args.NoTidy)
{
commandLine.Append(" -notidy");
}
// handle any previous outputs
if (0 < previousUnitResults.OutputFiles.Count && usePreviousOutput)
{
commandLine.AppendFormat(" \"{0}\"", previousUnitResults.OutputFiles[0]);
previousUnitResults.OutputFiles.Clear();
}
else // diff database files to create transform
{
commandLine.AppendFormat(" \"{0}\" \"{1}\"", targetDatabase, updatedDatabase);
}
if (null == outputFile || String.Empty == outputFile)
{
outputFile = Path.Combine(tempDirectory, "transform.mst");
}
commandLine.AppendFormat(" -out \"{0}\"", outputFile);
previousUnitResults.OutputFiles.Add(outputFile);
// run the tool
ArrayList output = ToolUtility.RunTool(toolFile, commandLine.ToString());
previousUnitResults.Errors.AddRange(ToolUtility.GetErrors(output, expectedErrors, expectedWarnings));
previousUnitResults.Output.AddRange(output);
// check the results
if (verifyTransform && 0 == expectedErrors.Length && 0 == previousUnitResults.Errors.Count)
{
string actualDatabase = Path.Combine(tempDirectory, String.Concat(Guid.NewGuid(), ".msi"));
File.Copy(targetDatabase, actualDatabase);
File.SetAttributes(actualDatabase, File.GetAttributes(actualDatabase) & ~FileAttributes.ReadOnly);
using (Database database = new Database(actualDatabase, OpenDatabase.Direct))
{
// use transform validation bits set in the transform (if any; defaults to None).
database.ApplyTransform(outputFile);
database.Commit();
}
// check the output file
ArrayList differences = CompareUnit.CompareResults(updatedDatabase, actualDatabase, testName, update);
previousUnitResults.Errors.AddRange(differences);
previousUnitResults.Output.AddRange(differences);
}
}
示例14: MergeModules
/// <summary>
/// Merges in any modules to the output database.
/// </summary>
/// <param name="tempDatabaseFile">The temporary database file.</param>
/// <param name="output">Output that specifies database and modules to merge.</param>
/// <param name="fileRows">The indexed file rows.</param>
/// <param name="suppressedTableNames">The names of tables that are suppressed.</param>
/// <remarks>Expects that output's database has already been generated.</remarks>
private void MergeModules(string tempDatabaseFile, Output output, FileRowCollection fileRows, StringCollection suppressedTableNames)
{
Debug.Assert(OutputType.Product == output.Type);
Table wixMergeTable = output.Tables["WixMerge"];
Table wixFeatureModulesTable = output.Tables["WixFeatureModules"];
// check for merge rows to see if there is any work to do
if (null == wixMergeTable || 0 == wixMergeTable.Rows.Count)
{
return;
}
IMsmMerge2 merge = null;
bool commit = true;
bool logOpen = false;
bool databaseOpen = false;
string logPath = null;
try
{
merge = NativeMethods.GetMsmMerge();
logPath = Path.Combine(this.TempFilesLocation, "merge.log");
merge.OpenLog(logPath);
logOpen = true;
merge.OpenDatabase(tempDatabaseFile);
databaseOpen = true;
// process all the merge rows
foreach (WixMergeRow wixMergeRow in wixMergeTable.Rows)
{
bool moduleOpen = false;
try
{
short mergeLanguage;
try
{
mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture);
}
catch (System.FormatException)
{
this.core.OnMessage(WixErrors.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language));
continue;
}
this.core.OnMessage(WixVerboses.OpeningMergeModule(wixMergeRow.SourceFile, mergeLanguage));
merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage);
moduleOpen = true;
// If there is merge configuration data, create a callback object to contain it all.
ConfigurationCallback callback = null;
if (!String.IsNullOrEmpty(wixMergeRow.ConfigurationData))
{
callback = new ConfigurationCallback(wixMergeRow.ConfigurationData);
}
// merge the module into the database that's being built
this.core.OnMessage(WixVerboses.MergingMergeModule(wixMergeRow.SourceFile));
merge.MergeEx(wixMergeRow.Feature, wixMergeRow.Directory, callback);
// connect any non-primary features
if (null != wixFeatureModulesTable)
{
foreach (Row row in wixFeatureModulesTable.Rows)
{
if (wixMergeRow.Id == (string)row[1])
{
this.core.OnMessage(WixVerboses.ConnectingMergeModule(wixMergeRow.SourceFile, (string)row[0]));
merge.Connect((string)row[0]);
}
}
}
}
catch (COMException)
{
commit = false;
}
finally
{
IMsmErrors mergeErrors = merge.Errors;
// display all the errors encountered during the merge operations for this module
for (int i = 1; i <= mergeErrors.Count; i++)
{
IMsmError mergeError = mergeErrors[i];
StringBuilder databaseKeys = new StringBuilder();
StringBuilder moduleKeys = new StringBuilder();
// build a string of the database keys
//.........这里部分代码省略.........
示例15: UpdateMSiTableGrid
/// <summary>
/// Shows the table in the list on the view table tab.
/// </summary>
/// <param name="msidb">The msi database.</param>
/// <param name="tableName">The name of the table.</param>
private void UpdateMSiTableGrid(Database msidb, string tableName)
{
if (msidb == null || string.IsNullOrEmpty(tableName))
return;
Status(string.Concat("Processing Table \'", tableName, "\'."));
using (new DisposableCursor(View))
{ // clear the columns no matter what happens (in the event the table doesn't exist we don't want to show anything).
View.ClearTableViewGridColumns();
try
{
// NOTE: Deliberately not calling msidb.TableExists here as some System tables could not be read due to using it.
string query = string.Concat("SELECT * FROM `", tableName, "`");
using (var view = new ViewWrapper(msidb.OpenExecuteView(query)))
{
foreach (ColumnInfo col in view.Columns)
{
View.AddTableViewGridColumn(string.Concat(col.Name, " (", col.TypeID, ")"));
}
View.SetTableViewGridDataSource(view.Records);
}
Status("Idle");
}
catch (Exception eUnexpected)
{
Error(string.Concat("Cannot view table:", eUnexpected.Message), eUnexpected);
}
}
}