I've created COM server using C# where my clients can receive real time updates.
Updates usually fired from different threads.
But I've noted that Excel crashes when callback methods updates spreadsheet.
Is there any way to call updates in UI thread?
P.S. I know about RTD feature of Excel. But it doesn't suit my needs because i need several parameters in one update.
what you are looking for is the Invoke / BeginInvoke Method of ISyncronizedInvoke
on your UI thread, take an arbitrary control and keep that reference ...
from the thread that wants to fire an update, call Invoke or BeginInvoke on that control (Control implements ISyncronizedInvoke) with a delegate that you want to execute on the UI thread ... from that delegate you may call your COM server
//EDIT: example code
using System;
using System.Windows.Forms;
using System.Threading;
using Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
Thread someWorkerThread;
Microsoft.Office.Interop.Excel.Application ExApp;
Worksheet wrkSheet;
public Form1()
{
InitializeComponent();
ExApp = new Microsoft.Office.Interop.Excel.Application();
ExApp.Visible = true; // or else we won't see the window
var books = ExApp.Workbooks;
var wrkBook = books.Add();
var sheets = wrkBook.Worksheets;
wrkSheet = sheets.get_Item(1);
Marshal.ReleaseComObject(sheets);
Marshal.ReleaseComObject(wrkBook);
Marshal.ReleaseComObject(books);
someWorkerThread = new Thread(new ParameterizedThreadStart(threadHandler));
someWorkerThread.Start(this);
}
private void threadHandler(object obj)
{// this will be executed on a seperate worker thread
Control mainFrm = obj as Control;
if (mainFrm == null)
throw new ArgumentException("Need to have a Control as parameter");
for (int i = 1; i < 50;i++ )
{
Thread.Sleep(2500);
mainFrm.Invoke(new Action<int>(doStuff), i); // this will invoke the main UI thread
}
}
private void doStuff(int i)
{// this will be executed on the main UI thread
var range = wrkSheet.Range[string.Format("A{0}", i)];
range.Value = "Hello World!";
Marshal.ReleaseComObject(range);
}
#region designer stuff
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(76, 84);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(149, 13);
this.label1.TabIndex = 0;
this.label1.Text = "I am an ordinary windows form";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 262);
this.Controls.Add(this.label1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label1;
#endregion
}
}
be advised: this example does not clean up the wrkSheet reference and the ExApp reference ... you have to release them before you exit your application
Related
There is a Microsoft Docs example which shows how to use a BackgroundWorker. And in the sample code is this comment, followed by an access to the BackgroundWorker via a sender parameter:
// Do not access the form's BackgroundWorker reference directly.
// Instead, use the reference provided by the sender parameter.
BackgroundWorker bw = sender as BackgroundWorker;
What error or behavior is being avoided here? And is this always necessary? For example, if I have a background worker that I create apart from a form, will this still be a good practice?
Full example from the link reproduced here for convenience:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
namespace BackgroundWorkerExample
{
public class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// Do not access the form's BackgroundWorker reference directly.
// Instead, use the reference provided by the sender parameter.
BackgroundWorker bw = sender as BackgroundWorker;
// Extract the argument.
int arg = (int)e.Argument;
// Start the time-consuming operation.
e.Result = TimeConsumingOperation(bw, arg);
// If the operation was canceled by the user,
// set the DoWorkEventArgs.Cancel property to true.
if (bw.CancellationPending)
{
e.Cancel = true;
}
}
// This event handler demonstrates how to interpret
// the outcome of the asynchronous operation implemented
// in the DoWork event handler.
private void backgroundWorker1_RunWorkerCompleted(
object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
// The user canceled the operation.
MessageBox.Show("Operation was canceled");
}
else if (e.Error != null)
{
// There was an error during the operation.
string msg = String.Format("An error occurred: {0}", e.Error.Message);
MessageBox.Show(msg);
}
else
{
// The operation completed normally.
string msg = String.Format("Result = {0}", e.Result);
MessageBox.Show(msg);
}
}
// This method models an operation that may take a long time
// to run. It can be cancelled, it can raise an exception,
// or it can exit normally and return a result. These outcomes
// are chosen randomly.
private int TimeConsumingOperation(
BackgroundWorker bw,
int sleepPeriod )
{
int result = 0;
Random rand = new Random();
while (!bw.CancellationPending)
{
bool exit = false;
switch (rand.Next(3))
{
// Raise an exception.
case 0:
{
throw new Exception("An error condition occurred.");
break;
}
// Sleep for the number of milliseconds
// specified by the sleepPeriod parameter.
case 1:
{
Thread.Sleep(sleepPeriod);
break;
}
// Exit and return normally.
case 2:
{
result = 23;
exit = true;
break;
}
default:
{
break;
}
}
if( exit )
{
break;
}
}
return result;
}
private void startBtn_Click(object sender, EventArgs e)
{
this.backgroundWorker1.RunWorkerAsync(2000);
}
private void cancelBtn_Click(object sender, EventArgs e)
{
this.backgroundWorker1.CancelAsync();
}
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
this.startBtn = new System.Windows.Forms.Button();
this.cancelBtn = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// backgroundWorker1
//
this.backgroundWorker1.WorkerSupportsCancellation = true;
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
//
// startBtn
//
this.startBtn.Location = new System.Drawing.Point(12, 12);
this.startBtn.Name = "startBtn";
this.startBtn.Size = new System.Drawing.Size(75, 23);
this.startBtn.TabIndex = 0;
this.startBtn.Text = "Start";
this.startBtn.Click += new System.EventHandler(this.startBtn_Click);
//
// cancelBtn
//
this.cancelBtn.Location = new System.Drawing.Point(94, 11);
this.cancelBtn.Name = "cancelBtn";
this.cancelBtn.Size = new System.Drawing.Size(75, 23);
this.cancelBtn.TabIndex = 1;
this.cancelBtn.Text = "Cancel";
this.cancelBtn.Click += new System.EventHandler(this.cancelBtn_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(183, 49);
this.Controls.Add(this.cancelBtn);
this.Controls.Add(this.startBtn);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
private System.ComponentModel.BackgroundWorker backgroundWorker1;
private System.Windows.Forms.Button startBtn;
private System.Windows.Forms.Button cancelBtn;
}
public class Program
{
private Program()
{
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
}
}
As #Hans Passant pointed out, sender and this.backgroundworker1 both reference the same object, and so do the same thing in the example. The reason for the warning is so if a future developer edits the backgroundWorker1_DoWork method to provide a different sender, sender will still work as intended, while this.backgroundworker1 might be accessing a backgroundworker which is no longer related to the method.
Working with:
Visual Studio 2017
NET framework 3.5
building for Any CPU
using 32-bit VLC version 2.2.6
using Vlc.DotNet (because i think it's only one that is working on any NET framework...)
I created new Form just for testing, how this library works (or if works)
used drag and drop method for "VlcControl" and one Button
All code is below:
Form.cs:
using System;
using System.IO;
using System.Windows.Forms;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog
{
Filter = "( *.mp4) | *.mp4"
};
if (ofd.ShowDialog() == DialogResult.OK)
{
vlcControl1.SetMedia(new FileInfo(Path.GetFileName(ofd.FileName)));
vlcControl1.Play();
}
}
}
}
Form.Designer.cs (Generated)
namespace WindowsFormsApp2
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.vlcControl1 = new Vlc.DotNet.Forms.VlcControl();
((System.ComponentModel.ISupportInitialize)(this.vlcControl1)).BeginInit();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(12, 255);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(260, 42);
this.button1.TabIndex = 1;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// vlcControl1
//
this.vlcControl1.BackColor = System.Drawing.Color.Black;
this.vlcControl1.Location = new System.Drawing.Point(12, 12);
this.vlcControl1.Name = "vlcControl1";
this.vlcControl1.Size = new System.Drawing.Size(260, 237);
this.vlcControl1.Spu = -1;
this.vlcControl1.TabIndex = 2;
this.vlcControl1.Text = "vlcControl1";
this.vlcControl1.VlcLibDirectory = new System.IO.DirectoryInfo("C:\\Program Files (x86)\\VideoLAN\\VLC");
this.vlcControl1.VlcMediaplayerOptions = null;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 309);
this.Controls.Add(this.vlcControl1);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.vlcControl1)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button button1;
private Vlc.DotNet.Forms.VlcControl vlcControl1;
}
}
Program.cs
using System;
using System.Windows.Forms;
namespace WindowsFormsApp2
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
Now the question is:
After calling "InitializeComponent()", program crashes:
In file: Form.Designer.cs
Line with:
((System.ComponentModel.ISupportInitialize)(this.vlcControl1)).EndInit();
throws System.ComponentModel.Win32Exception: '%1 is not a valid Win32 application'
How can i fix it???
Just set: Project-> Properties-> Build -> Platform Target = x86
A stack overflow is occurring in the auto-generated code for my winform. It happens only at the start of the auto-generated code for the form, not any of the controls in it. I tried removing the first line, and it happened on the next one. There is no stack trace or inner exception, please help.
EDIT
Here is my code for the form:
namespace Eternal_Continent
{
public partial class Almanac : Form
{
public Almanac()
{
InitializeComponent();
}
public List<string> Content = new List<string>();
private void Almanac_Load(object sender, EventArgs e)
{
timer1.Interval = 5000;
PrivateFontCollection pfc = new PrivateFontCollection();
pfc.AddFontFile(Application.StartupPath + "\\Resources\\font_name.ttf");
textBox1.Font = new Font(pfc.Families[0], 36);
}
private void Almanac_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
Hide();
}
}
}
And here is the designer's:
namespace Eternal_Continent
{
partial class Almanac
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Almanac));
this.textBox1 = new System.Windows.Forms.TextBox();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// textBox1
//
this.textBox1.BackColor = System.Drawing.Color.Khaki;
this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.textBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.textBox1.Location = new System.Drawing.Point(0, 0);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.ReadOnly = true;
this.textBox1.Size = new System.Drawing.Size(546, 582);
this.textBox1.TabIndex = 0;
//
// timer1
//
this.timer1.Enabled = true;
//
// Almanac
// I removed the autoscale lines here, because I wanted to see if it would still create errors, it did
this.BackgroundImage = Properties.Resources.Stone;
this.ClientSize = new System.Drawing.Size(546, 582);
this.Controls.Add(this.textBox1);
this.Icon = Properties.Textures.EternalContinent1;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Almanac";
this.Text = "Almanac";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Almanac_FormClosing);
this.Load += new System.EventHandler(this.Almanac_Load);
this.ResumeLayout(false);
this.PerformLayout();
this.Dispose();
}
#endregion
private System.Windows.Forms.Timer timer1;
public System.Windows.Forms.TextBox textBox1;
}
}
EDIT #2
Removing the Dispose() line causes
The current process has used all of its system allowance of handles for Window Manager objects
in my Resources.Designer.cs.
I tried your code and I got an ObjectDisposed exception. On debugging it turns out that your Auto-generated code has the last line as this.Dispose(), which is incorrect.
Once I deleted that line (last line of InitializeComponent() ) the designer and the code worked fine without any errors
Note that I had to comment out the below lines related to the resources since I do not have that in my project & file-system
// Almanac.cs
pfc.AddFontFile(Application.StartupPath + "\\Resources\\font_name.ttf");
// Almanac.Designer.cs
this.BackgroundImage = Properties.Resources.Stone;
this.Icon = Properties.Textures.EternalContinent1;
You should also comment out these lines from your code to make sure you get the same results as I get, and then include them one at a time to make sure they are not causing any issues
NOTE: I am using VS 2013 on Win 7
Often this will be down to accidental, indirect recursion. I have an old answer here that might help: https://stackoverflow.com/a/4734422/26414
It's also worth noting that if you step through using F11 you might see the looping pattern that tells you what's what. Be aware of which thread you're debugging, too. I believe you get a darker yellow highlight for the current line when stepping-through, if there are multiple threads with user code executing.
At the moment I am developing an application and want to add a Windows (7) JumpList. I followed several tutorials and studied documentation, but I can't figure out how to get the job done. In short: I want a recent list of last choosen files. So after closing the app, the user can easily open a recent file with my application. I already implemented some file association mechanism.
Is it possible to share some code/ tutorial how I can solve above problem?
Thank you in advance!
*I already tried the next few projects/ tutorials:
http://www.codeproject.com/Articles/103913/How-to-Create-a-Custom-Jumplist-with-Custom-Events
http://channel9.msdn.com/coding4fun/articles/Windows-7-Jump-Lists
http://csharp-tricks-en.blogspot.nl/2011/10/create-jumplist-using-c.html
*The code of Coding 4 Fun works, but I don't know how to develop a recent file list.
You can check out this article. Instead of showing result in WPF you need to show it in jumplist.
Why dont you try storing the recently opened file names in a database or an xml file and read it to set the jumplist. For eg.
private void ReportUsage()
{
XmlDocument myXml = new XmlDocument();
myXml.Load(historyXml);
string list = historyXml;
jumpList.ClearAllUserTasks();
foreach (XmlElement el in myXml.DocumentElement.ChildNodes)
{
string s = el.GetAttribute("url");
JumpListLink jll = new JumpListLink(Assembly.GetEntryAssembly().Location, s);
jll.IconReference = new IconReference(Path.Combine("C:\\Program Files\\ACS Digital Media\\TOC WPF Browser\\Icon1.ico"), 0);
jll.Arguments = el.GetAttribute("url");
jumpList.AddUserTasks(jll);
}
jumpList.Refresh();
}
Or a beginners solution will be retain all the file paths into a Queue of given maximum capacity and adding them at run-time into a menuItem. Sorry I didnt have time to write the whole code.
As it is described in your second article, your application must be registered as a handler for targeted file extension, otherwise the recent category for your Jumplist won't show up. You can find more details about file association registration there.
You can either manually register your application but you will need admin right so it is not recommended, or create a setup project for your application like described in the coding 4 fun article, or you can let the user associate the file extension.
Here is a sample which works for me under Windows Seven without registration, by just right clicking the text file I want to load and choosing "Open With" and browse to my application.
The sample require Windows API Code Pack
public partial class Form1 : Form
{
[STAThread]
static void Main(string[] args)
{
var file = args != null && args.Length > 0 ? args[0] : string.Empty;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(file));
}
public Form1()
: this(string.Empty)
{
}
public Form1(string file)
{
InitializeComponent();
Open(file);
}
[DllImport("user32.dll")]
private static extern uint RegisterWindowMessage(string message);
private uint wmTBC;
/// <summary>
/// Registers the window message for notification when the taskbar button is created.
/// </summary>
/// <param name="e">The event args.</param>
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
wmTBC = RegisterWindowMessage("TaskbarButtonCreated");
}
/// <summary>
/// Handles the window message for notification of the taskbar button creation.
/// </summary>
/// <param name="m">The window message.</param>
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == wmTBC)
{
OnTaskbarButtonCreated();
}
}
/// <summary>
/// Override this method to recieve notification when the taskbar button is created on Windows 7 machines and above.
/// </summary>
protected void OnTaskbarButtonCreated()
{
if (TaskbarManager.IsPlatformSupported)
{
jumpList = JumpList.CreateJumpList();
jumpList.KnownCategoryToDisplay = JumpListKnownCategoryType.Recent;
jumpList.Refresh();
}
}
JumpList jumpList;
private void openToolStripMenuItem1_Click(object sender, EventArgs e)
{
using (OpenFileDialog ofd = new OpenFileDialog())
{
if (ofd.ShowDialog() == DialogResult.OK)
{
Open(ofd.FileName);
}
}
}
private void Open(string file)
{
try
{
if (!string.IsNullOrEmpty(file) && File.Exists(file))
{
textBox1.Text = File.ReadAllText(file);
if (TaskbarManager.IsPlatformSupported)
{
jumpList.AddToRecent(file);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.openToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.menuStrip1.SuspendLayout();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(12, 27);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(796, 306);
this.textBox1.TabIndex = 0;
//
// menuStrip1
//
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.openToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(820, 24);
this.menuStrip1.TabIndex = 1;
this.menuStrip1.Text = "menuStrip1";
//
// openToolStripMenuItem
//
this.openToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.openToolStripMenuItem1});
this.openToolStripMenuItem.Name = "openToolStripMenuItem";
this.openToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
this.openToolStripMenuItem.Text = "File";
//
// openToolStripMenuItem1
//
this.openToolStripMenuItem1.Name = "openToolStripMenuItem1";
this.openToolStripMenuItem1.Size = new System.Drawing.Size(152, 22);
this.openToolStripMenuItem1.Text = "Open";
this.openToolStripMenuItem1.Click += new System.EventHandler(this.openToolStripMenuItem1_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(820, 345);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.menuStrip1);
this.MainMenuStrip = this.menuStrip1;
this.Name = "Form1";
this.Text = "Form1";
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.MenuStrip menuStrip1;
private System.Windows.Forms.ToolStripMenuItem openToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem openToolStripMenuItem1;
}
Using a ListView, I need to display (large) icons for an array of executables.
Is there a standard way of doing this / a "Pattern" (whether Design or otherwise)?
A wrinkle: these .exes should be runnable from this ListView ONLY. If a person were to navigate to the .exe via Explorer, they should not be able to run them from there. IOW, the user must log in to the system before seeing the array of program icons (and what they see will depend on their role)*, and that is the ONLY gateway to run those apps.
So, these app icons must be added programmatically.
Ideas?
Update:
Trying to use the code below to create a "Quick and Dirty" app.
Here's my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace ListViewWithAppIcons {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
DirectoryInfo dir = new DirectoryInfo(#"C:\SpotRun");
foreach (FileInfo file in dir.GetFiles()) {
try {
this.imageList1.Images.Add(Image.FromFile(file.FullName));
} catch {
Console.WriteLine("This is not a Duck-billed Platypus");
}
}
this.listView1.View = View.LargeIcon;
this.imageList1.ImageSize = new Size(32, 32);
this.listView1.LargeImageList = this.imageList1;
//or
//this.listView1.View = View.SmallIcon;
//this.listView1.SmallImageList = this.imageList1;
for (int j = 0; j < this.imageList1.Images.Count; j++) {
ListViewItem item = new ListViewItem();
item.ImageIndex = j;
this.listView1.Items.Add(item);
}
}
}
}
..and here's the "code generated by a tool" (not me, the other tool):
namespace ListViewWithAppIcons {
partial class Form1 {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.components = new System.ComponentModel.Container();
this.listView1 = new System.Windows.Forms.ListView();
this.imageList1 = new System.Windows.Forms.ImageList(this.components);
this.SuspendLayout();
//
// listView1
//
this.listView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.listView1.Location = new System.Drawing.Point(0, 0);
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(555, 408);
this.listView1.TabIndex = 0;
this.listView1.UseCompatibleStateImageBehavior = false;
//
// imageList1
//
this.imageList1.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit;
this.imageList1.ImageSize = new System.Drawing.Size(16, 16);
this.imageList1.TransparentColor = System.Drawing.Color.Transparent;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(555, 408);
this.Controls.Add(this.listView1);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ListView listView1;
private System.Windows.Forms.ImageList imageList1;
}
}
Hi Clay, I need to reference a superfluous Princess Bride!
An example off MSDN so you know your coding it up sweet:
private void Form_Load(object sender, EventArgs e)
{
DirectoryInfo dir = new DirectoryInfo(#"c:\pic");
foreach (FileInfo file in dir.GetFiles())
{
try
{
this.imageList1.Images.Add(Image.FromFile(file.FullName));
}
catch
{
Console.WriteLine("This is not an image file");
}
}
this.listView1.View = View.LargeIcon;
this.imageList1.ImageSize = new Size(32, 32);
this.listView1.LargeImageList = this.imageList1;
//or
//this.listView1.View = View.SmallIcon;
//this.listView1.SmallImageList = this.imageList1;
for (int j = 0; j < this.imageList1.Images.Count; j++)
{
ListViewItem item = new ListViewItem();
item.ImageIndex = j;
this.listView1.Items.Add(item);
}
}
To prevent people from opening the exe's (except from your program) is pretty hard, it would be easy if you wrote all those applications and could require a secret argument (as in like a command line arg) be passed in to start the other applications. But using Process Monitor/Explorer users could find out the secret key.
Alternatively you could hide the exe's in some folder but the trick here is that the name of the exe will be shown in Task Manager and once users see this they could search for the exe. I mean you could get around this using my technique here, but how deep is the rabits hole: How to hide C# application from taskmanager processtab? - see my answer, its got the most votes.
Maybe a better solution than all this mucking around hiding stuf from users would be - Kiosk mode: http://support.microsoft.com/kb/555463