|
Well, I implemented what you suggested (without a clear understanding of what it all does), but it doesn't seem to have solved my problem.
What I'm hoping for is something that will make it so that when the set() function for my X Property returns, it calls the set() function for my Vector Property. Was that the intent of what you gave me? If so, perhaps I have done something wrong. Because it is not currently doing that.
NotifyParentProperty(true) looks very promising. How does that work exactly. Is the TypeConverter necessary for that to work?
|
|
|
|
|
Eric Burns wrote: Is the TypeConverter necessary for that to work
Not sure about that.
I'll go away and dig out some working code. Get back to you shortly.
Honi soit qui mal y pongs - Evil to he who thinks it stinks
|
|
|
|
|
My working examples are complicated and it is taking a while to whittle them down enough to be clear.
Meanwhile, look here[^] MS has an example that has pretty much everything I talked about. Just add the two overrides to the BorderAppearanceConverter.
I'll get back to you when I've finished refactoring.
Honi soit qui mal y pongs - Evil to he who thinks it stinks
|
|
|
|
|
Sorry to have been so long. Had some interesting problems, which I'll tell you about later.
First the working code, as promised.
A simple Vector class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace TestControlLibrary
{
[
Serializable,
TypeConverter(typeof(TestControlLibrary.TCLVectorConverter))
]
public class Vector
{
private int x = 0;
private int y = 0;
private int z = 0;
public Vector(int x, int y, int z)
{
this.x = x;
this.y = y;
this.z = z;
}
[
NotifyParentProperty(true)
]
public int X
{
get
{
return this.x;
}
set
{
if (this.x != value)
{
this.x = value;
}
}
}
[
NotifyParentProperty(true)
]
public int Y
{
get
{
return this.y;
}
set
{
if (this.y != value)
{
this.y = value;
}
}
}
[
NotifyParentProperty(true)
]
public int Z
{
get
{
return this.z;
}
set
{
if (this.z != value)
{
this.z = value;
}
}
}
}
}
The Converter
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Reflection;
namespace TestControlLibrary
{
public class TCLVectorConverter : ExpandableObjectConverter
{
public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
{
return true;
}
public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues)
{
return new Vector((int)propertyValues["X"], (int)propertyValues["Y"], (int)propertyValues["Z"]);
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
bool result = false;
if (sourceType == typeof(string))
{
result = true;
}
else
{
result = base.CanConvertFrom(context, sourceType);
}
return result;
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
Vector result = null;
if (value is string)
{
try
{
string propertyList = (string)value;
string[] properties = propertyList.Split(',');
result = new TestControlLibrary.Vector(Convert.ToInt32(properties[0]), Convert.ToInt32(properties[1]),
Convert.ToInt32(properties[2]));
}
catch
{
throw new ArgumentException("The arguments are not valid for a Vector.");
}
}
else
{
result = (Vector)base.ConvertFrom(context, culture, value);
}
return result;
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return ((destinationType == typeof(string)) || (destinationType == typeof(InstanceDescriptor)));
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
object result = null;
if (value is TestControlLibrary.Vector)
{
if (destinationType == typeof(string))
{
StringBuilder stringResult = new StringBuilder();
TestControlLibrary.Vector vector = (TestControlLibrary.Vector)value;
stringResult.AppendFormat("{0}, {1}, {2}", vector.X, vector.Y, vector.Z);
result = stringResult.ToString();
}
if (destinationType == typeof(InstanceDescriptor))
{
TestControlLibrary.Vector vector = (TestControlLibrary.Vector)value;
object[] properties = new object[3];
Type[] types = new Type[3];
types[0] = typeof(int);
properties[0] = vector.X;
types[1] = typeof(int);
properties[1] = vector.Y;
types[2] = typeof(int);
properties[2] = vector.Z;
ConstructorInfo ci = typeof(TestControlLibrary.Vector).GetConstructor(types);
result = new InstanceDescriptor(ci, properties);
}
}
else
{
result = base.ConvertTo(context, culture, value, destinationType);
}
return result;
}
}
}
If you build this and place an instance of TestControl on a form you will find that you can set the vector properties, it appears in the Misc category cos I didn't set a Category Attribute, on the one line e.g. 5, 10, 20 OR you can expand the Vector property and set X, Y or Z individually. In exactly the same way that the Location or Size properties can be set. Whichever way you do it the properties are set on the control instantly, because even when you set the individual sub-properties responsibility passes up to Vector to do the setting.
AND NOW FOR SOMETHING COMPLETELY DIFFERENT
The problems I had was with the converter , more specifically with its name. You will notice that it is called TCLVectorConverter in the code above.
When in my earlier message I said I had working code, I was not telling fibs, I really did, but to be super helpful I renamed my component to Vector to match your original post. When I tried to use the code I kept getting errors from the designer that it could not serialize Vector .
It took ages and ages for me to discover the cause was the name VectorConverter . When I renamed it as above it all worked perfectly.
I know why I was getting errors, but do not understand it. There is a Vector class in System.Windows , but that ain't the problem. There is also a VectorConverter class in System.Windows and that IS the problem. Even though I went through the code qualifying all references to Vector and VectorConverter (TestControlLibrary.Vector and TestControlLibrary.VectorConverter ), somehow and in some way there was a clash with the System.Windows version of VectorConverter . Maybe a wiser head than mine can explain it, but I am at a loss.
Once you have working code, you might, just for laughs, rename TCLVectorConverter back to plain VectorConverter to watch the fun.
Never the less working code, as promised.
Ain't coding f%&*ing fun.
Honi soit qui mal y pongs - Evil to he who thinks it stinks
|
|
|
|
|
Here's the code for the control using Vector. I've split it in two because of the length.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace TestControlLibrary
{
[Serializable]
public partial class TestControl : UserControl
{
private Vector vector;
public TestControl()
{
InitializeComponent();
this.vector = new Vector(10, 10, 10);
this.RefreshVectorDisplay();
}
private void RefreshVectorDisplay()
{
this.txtX.Text = this.vector.X.ToString();
this.txtY.Text = this.vector.Y.ToString();
this.txtZ.Text = this.vector.Z.ToString();
}
public Vector Vector
{
get
{
return this.vector;
}
set
{
if (this.vector != value)
{
this.vector = value;
this.RefreshVectorDisplay();
}
}
}
}
}
and its designer code
namespace TestControlLibrary
{
partial class TestControl
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
private void InitializeComponent()
{
this.txtX = new System.Windows.Forms.TextBox();
this.txtY = new System.Windows.Forms.TextBox();
this.txtZ = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.SuspendLayout();
this.txtX.Location = new System.Drawing.Point(35, 30);
this.txtX.Name = "txtX";
this.txtX.Size = new System.Drawing.Size(100, 20);
this.txtX.TabIndex = 0;
this.txtY.Location = new System.Drawing.Point(35, 63);
this.txtY.Name = "txtY";
this.txtY.Size = new System.Drawing.Size(100, 20);
this.txtY.TabIndex = 1;
this.txtZ.Location = new System.Drawing.Point(35, 96);
this.txtZ.Name = "txtZ";
this.txtZ.Size = new System.Drawing.Size(100, 20);
this.txtZ.TabIndex = 2;
this.label1.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(55, 8);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(40, 14);
this.label1.TabIndex = 3;
this.label1.Text = "Vector";
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(14, 33);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(17, 14);
this.label2.TabIndex = 4;
this.label2.Text = "X:";
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(12, 66);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(18, 14);
this.label3.TabIndex = 5;
this.label3.Text = "Y:";
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(12, 99);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(17, 14);
this.label4.TabIndex = 6;
this.label4.Text = "Z:";
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 14F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.MistyRose;
this.Controls.Add(this.label4);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.txtZ);
this.Controls.Add(this.txtY);
this.Controls.Add(this.txtX);
this.Name = "TestControl";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox txtX;
private System.Windows.Forms.TextBox txtY;
private System.Windows.Forms.TextBox txtZ;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
}
}
Honi soit qui mal y pongs - Evil to he who thinks it stinks
|
|
|
|
|
Thank you very, very much for your help. But unfortunately, this won't call the setter on my parent property, it will only update it in the control display. I think I'll need to use the event-based solution suggested by Pete O'Hanlon, et al.
But! Your work is not for naught! You have taught me something very important that I can apply on other parts of the project. So, while this doesn't solve my initial problem, it solves others. So, thank you very, very much!
|
|
|
|
|
Glad to (sort of) help.
Henry Minute
If you open a can of worms, any viable solution *MUST* involve a larger can.
|
|
|
|
|
This is generally off-topic...but I am curious anyway. Do you really have a class called 'Object'? The only reason I ask is because System.Object is central to every type in all of .NET, and creating an alternative Object class could pose its own problems (wherever the alternative Objects namespace is used)...perhapse is even contributing to your problems?
|
|
|
|
|
No, it's not really called Object. ;o) Thanks for checking me out, though. ;o)
|
|
|
|
|
Ok...good. I had to make sure.
|
|
|
|
|
Well, one way to do this could be to implement INotifyPropertyChanged like so:
public class Vector : INotifyPropertyChanged
{
private int _x;
private int _y;
private int _z;
public int X
{
get
{
return _x;
}
set
{
if (_x != value)
{
_x = value;
Changed("X");
}
}
}
public int Y
{
get
{
return _y;
}
set
{
if (_y != value)
{
_y = value;
Changed("Y");
}
}
}
public int Z
{
get
{
return _z;
}
set
{
if (_z != value)
{
_z = value;
Changed("Z");
}
}
}
private void Set()
{
}
#region INotifyPropertyChanged Members
private PropertyChangedEventHandler _propertyChanged;
public event PropertyChangedEventHandler PropertyChanged
{
add
{
_propertyChanged += value;
}
remove
{
_propertyChanged -= value;
}
}
protected virtual void Changed(string propertyName)
{
Set();
PropertyChangedEventHandler handler = _propertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
} As noted in the Set method, you can rely on the event being raised so that the container can respond to any changes you've introduced as a result of the Set method.
|
|
|
|
|
Hi,
I am trying a sample program...to create C# source code from a simple flow chart prepared in visio(not UML models). Please give me any ideas, to start it or let me know are there any tools available to do my job.
Thanks in advance
By,
sree
sree
|
|
|
|
|
Your application is going to need some heavy work in it's ability to plan, design, and generate code. Most flowcharts simply don't provide enough information to generate code like you want. Also, your app is (I can't believe I'm saying this) going to have to understand English in order to do this.
|
|
|
|
|
Hi,
I am attempting to create a service to watch particular directories for excessively large files being created. I've created a Created event handler with the following code:
void fileSystemWatcher1_Created(object sender, FileSystemEventArgs e)
{
FileInfo fi = new FileInfo(e.FullPath);
if (fi.Length > 524288000)// 500MB = 524288000
{
smtpMessage.Body = "A file exceeding 500 MB has been created at " + e.FullPath.ToUpper();
Client.Send(smtpMessage);
}
}
I drop files one at a time into the watched directory and I'll get an email alert for the first file but nothing for subsequent files? Any help greatly appreciated.
C. Richard Wenger
System Administrator
|
|
|
|
|
How are you initializing the watcher?
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001
|
|
|
|
|
This is what I have setup:
this.fileSystemWatcher1.Path = directoryPath1;
this.fileSystemWatcher1.IncludeSubdirectories = true;
this.fileSystemWatcher1.Filter = "*.*";
this.fileSystemWatcher1.Created += new FileSystemEventHandler(fileSystemWatcher1_Created);
C. Richard Wenger
System Administrator
|
|
|
|
|
You haven't set a NotifyFilter , and you haven't turned on EnableRaisingEvents ...
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001
|
|
|
|
|
Sorry, I've got EnableRaisingEvents = true in the OnStart method for the service. I'm not certain how I would code a NotifyFilter since none of them seem to relate to file size?
C. Richard Wenger
System Administrator
|
|
|
|
|
There are no file size filters in the FSW. The filter is just there so the FSW knows which events you want to check for.
The FSW polls the filesystem, taking snapshot after snapshot of the monitored directies and their files Created and LastModified times. Then it compares the new snapshot with the old one, generating the required events based on the differences between the two snapshots, subject to the NotifyFilter specification.
|
|
|
|
|
Well, I see a NotifyFilters.Size - isn't that what you want?
At the same time, it might be better to filter on NotifyFilters.LastWrite so that you only have to deal with one event when the file is closed. At that point, you see how big the file is, and act accordingly, but you only do it once per file. Much more efficient.
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001
|
|
|
|
|
I looking over what you've said and I'm trying to see if there is a way I can leverage this to a useable outcome. As I read it the NotifyFilters.Size reports a CHANGE in file size and I'm not certain how I could use this in my application. The goal is to send email alerts only when files are copied into a directory over a predertimed size limit (if that helps).
C. Richard Wenger
System Administrator
|
|
|
|
|
Then you want to set the LastWrite filter. That way, when the file is closed, you'll be notified, and you can check the size. If your goal is to determine the size of the file *before* it's written, I don't think that's possible.
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001
|
|
|
|
|
rich_wenger wrote: FileInfo fi = new FileInfo(e.FullPath);
if (fi.Length > 524288000)// 500MB = 524288000
This isn't going to work. When a file is created, it's length is always 0. Only when the application flushes it's writes to the file does the filesize increase, for which there is NO FSW event.
Your code has to keep track of the files that are new, then occasionally check back with those files to get their current sizes, then you can do what's necessary.
|
|
|
|
|
I think I understand what you are saying, I am just not certain why I am getting the first email alert?
C. Richard Wenger
System Administrator
|
|
|
|
|
FSW events don't fire exactly when the actual event occurs. In your case, it appears that the system was doning something else, blocking your application, but still queueing up the Create event. By the time your Create handler got called, the file had attained the require size to trip the email.
|
|
|
|
|