Library of Custom Controls in Winforms - winforms

I wanted a TextBox with just digits as entry. So i wrote following code in the KeyPress events of the textbox
if(!char.IsDigit(e.KeyChar))
{
e.handled = true;
}
and it worked great. But I generally need them in many places of my application so then i wrote a partial class with following codes:
public partial class digitTextBox : TextBox
{
public digitTextBox()
{
this.KeyPress += new KeyPressEventHandler(digitTextBox_KeyPress);
}
void digitTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
}
}
build my solution and I got a control in my toolbox and even this was working perfectly fine.
But i had many TextBoxes with some or the other specification like, some should not accept special characters, some should accept decimals, some with decimals up to 2 digits after point....and so on and i do need these kind of controls in many applications.
So I thought of writing a Library(.dll) of my custom controls and if possible even for there validations. Honestly speaking I don't have much idea about using libraries. So I made a library with 2 different kind of textboxes and created a .dll file out of them. Now I created a different winform application and I added reference of my custom control .dll file. But nothing happened.
So i just wanted to know what should be my approach in achieving it. Is there a better way to achieve these kind of tasks. and any new suggestions are also welcome. Thanks in advance.

Try right-mouse clicking the ToolBox and select "Choose Items..." and then select your controls from the available list. If you don't see them, then click on the Browse button and select your DLL.
On a side note, you might be able to combine your two textboxes by adding properties:
public class MyTextBox : TextBox
{
public bool AllowDigitsOnly { get; set; }
protected override void OnKeyPress(KeyPressEventArgs e)
{
if (this.AllowDigitsOnly)
{
if (!char.IsDigit(e.KeyChar))
e.Handled = true;
}
base.OnKeyPress(e);
}
}

I would suggest implementing a single custom control, which controls input based on a regular expression. Instead of limiting keypresses, I would prevent the control loosing focus if its text does not match the regular expression. Some change in background color or a popup ballon can be used to display errors and/or a description of what the input is supposed to be.

I did something similar and what helped me was to add properties to my textbox instead of creating 2 different types for integers and doubles (basically allowing a decimal for my requirements).
By creating a property, you can actually choose whether you want the textbox as integer or double in the Properties view at design-time. Just like how you have Font, ReadOnly etc that you set during design time.
Here is my code to make the properties,
/// <summary>
/// Identify textbox type as integer or double
/// </summary>
public enum numericID
{
Integer,
Double
};
/// <summary>
/// Textbox type property, default is integer
/// </summary>
private numericID numericType = numericID.Integer;
/// <summary>
/// Getter and setter for property
/// </summary>
[Browsable(true),
DisplayName("TextBoxType"),
DefaultValue(numericID.Integer),
Description("Indicates whether the textbox must only accept integers or doubles."),
Category("Behavior")]
public numericID NumericType
{
get { return numericType; }
set { numericType = value; }
}
and the onKeyPress event is actually quite handy from the msdn website. It handles all different types of characters for numerics and you can choose whichever one works best for you.

Related

Update WPF Window Asynchronously

I am creating a simple WPF app that when you click on a button it runs through a few steps like copy the file to a new location, convert the file then it copies the new file back to the original location.
The steps are working fine but I would like to have the WPF window update to which step it is on and hide the button while it is running.
The window only updates once it has finished running my code. I think I used to be able to do this on classic forms with me.refresh but this doesn't work on WPF.
Is something I can do to update the window after each step is complete?
Thank you
Button1.Visibility = Windows.Visibility.Hidden
FileCopy("C:\Test.xsf", AppPath & "\Convert\test.xsf")
Image7.Visibility = Windows.Visibility.Hidden
Image3.Visibility = Windows.Visibility.Visible
Program.StartInfo.FileName = xDefs
Program.StartInfo.Arguments = "/q"
Program.Start()
Program.WaitForExit()
Image5.Visibility = Windows.Visibility.Visible
FileCopy("AppPath & "\Convert\test.csv, "C:\Test.csv")
Button1.Visibility = Windows.Visibility.Visible
In order to update the UI while your program is busy, you'll need to use the Dispatcher class to add your update request onto the UI message queue. Take this synchronous example:
public void DoWorkWithFile(string filePath)
{
CopyFile(filePath);
ConvertFile(filePath);
CopyFileBack();
}
We could use the Dispatcher class to break this up and feed messages back to the UI in between tasks:
public void DoWorkWithFile(string filePath)
{
CopyFile(filePath);
RunOnUiThread((Action)delegate { SomeUiTextBlock.Text = "Copied" });
ConvertFile(filePath);
RunOnUiThread((Action)delegate { SomeUiTextBlock.Text = "Converted" });
CopyFileBack();
RunOnUiThread((Action)delegate { SomeUiTextBlock.Text = "Copied back" });
}
private object RunOnUiThread(Action method)
{
return Dispatcher.Invoke(DispatcherPriority.Normal, method);
}
I know this is a VB.NET tagged question but I'll just go ahead and share a C# solution. I hope you know enough of it to port it to VB. This is the first time and posting anything to stackoverflow, if it solves your problem please mark it as the answer :-)
You must first know a thing or two (actually a lot more) on data binding. You basically create a view model, define the property that changes with time and bind this to the window. In this case you must define a value to keep track of the current operation and let the button control.
Disclaimer, I wrote this in notepad and haven't tested it on visual studio. Be on the lookout for typos.
using System.ComponentModel;
namespace FileConverter
{
//define the various states the application will transition to
public enum OperationStatus
{
CopyingFileToNewLocation
ConvertingFile,
CopyingFileToOriginalLocation
OperationCompelete
}
//Defines the view model that shall be bound to the window.
//The view model updates the UI using event notifications. Any control that had enabled
//binding will get updated automatically
public class ViewModel : INotifyPropertyChanged//This interface defines an event used to raise an event and notify subscribers of a changed in data
{
private OperationStatus _FileConvertionStatus;
public event PropertyChangedEventHandler PropertyChanged;
public OperationStatus FileConvertionStatus
{
get
{
return _FileConvertionStatus;
}
set
{
_FileConvertionStatus=value;
//Notify all UIElements / objects that had subscribed to this property that it has changed
RaisePropertyChanged(this,"FileConvertionStatus");
}
}
public void RaisePropertyChanged(object sender,string propertyName)
{
//check if there is any object that had subscribed to changes of any of the data properties in the view model
if(PropertyChanged!=null)
PropertyChanged(sender,new PropertyChangedEventArgs(propertyName));
}
public void StartFileConvertion(string filePath)
{
//Any time we change the property 'FileConvertionStatus', an event is raised which updates the UI
this.FileConvertionStatus=OperationStatus.CopyingFileToNewLocation;
StartCopyingToNewLocation(); //call your copying logic
this.FileConvertionStatus=OperationStatus.ConvertingFile;
StartFileConvertion(); //call your conversion logic
this.FileConvertionStatus=OperationStatus.CopyingFileToOriginalLocation();
CopyFileToOriginalLocation(); //...
this.FileConvertionStatus=OperationStatus.OperationCompelete;
}
}
}
//Now for the UI section
In the constructor of the window, you must bind the window to the view model right after this window has been initialized
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ViewModel vm=new ViewModel();
//setting the data context property the window implicitly binds the whole window to our view model object
this.DataContext=vm;
string filePath="c:\file.txt";
//start the file manipulation process
vm.StartFileConvertion(filePath);
}
}
//Next step we need to bind the button to the 'FileConvertionStatus' property located in the view model. We don't bind the button to the whole view model, just the property that it's interested in. Having bound the window to the view model in the previous code, all child elements get access to the public properties of this view model (VM from now on). We do the property binding in XAML
..Button x:Name="btnStartFileProcessing" Enabled="{Binding FileConvertionStatus}"...
We're almost there. One this is missing. You'll notice that the 'Enabled' property is a Boolean value. The 'FileConvertionStatus' property is enum. Same way you can't assign an enum to a Boolean directly, you need to do some convertion. This is where converters come in.
Converters allow you to define how one property can be converted to a different one in XAML. In this case we want the button to be enabled only when file conversion is successful. Please do some reading into this.
Create a class as shown below:
using System.Windows.Data;
namespace FileConverter
{
public class OperationStatusToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType,object parameter,System.Globalization.CultureInfo culture)
{
OperationStatus status=(OperationStatus)value;
switch(status)
{
case OperationStatus.OperationCompelete:
return true; //enable the button when everything has been done
default:
return false;//disable the button as the file processing is underway
}
}
public object ConvertBack(object value, Type targetType,object parameter,System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Next step is to define the converter in XAML code. Think of this as initializing it though it can't be further from the true :-). Its more of importing the namespace into the xaml.Put the code below in the App.XAML file. Doing such declaration in the App.XAML file makes the code visible globally.
xmlns:MyConverters="clr-namespace:FileConverter"
In the Application.Resources XAML tag, declare the converter as shown below
<Application.Resources>
<MyConverters:OperationStatusToBooleanConverter x:Key="OperationStatusToBooleanConverter"/>
</Application.Resources>
Final Step
Redo the binding code in the button to include the converter.
...Button Enabled="{Binding FileConvertionStatus,Converter={StaticResource OperationStatusToBooleanConverter}}" x:Name="btnStartFileProcessing" ...
Please note that I haven't thread-optimized this code, the main problem is that all work is being done on the UI thread which can lead to the window hanging if an operation takes long.
The amount of work needed to properly set the binding up as per MVVM code standards is a lot. It might seem like an over-kill and at times, it actually is. Keep this in mind though, once the UI gets complex MVVM will definitely save the day due to the separation of concerns and binding strategies.

How, in Silverlight, can one keep the contents of a user control completely private?

I'm creating a user control to contain credit card information provided by the user. The control collects account number, expiration, and CCV.
I want the only output from this control to be a single property representing an encrypted string.
I already have this property, and I've made my control's private and set up binding in a way that it doesn't use public properties. All that is working. I just want to somehow disable visual tree searching and the FindName method from being able to excise the credit card information from the control.
I am aware that this seems overzealous, but can is there even a way to do this?
You could try not storing the information in a control. How about processing it from BackgroundWorker or something else that isn't seen by the VisualTree? Then communicate back to the control using the encrypted string only.
Have you looked at how it's done in the templated SL BussinessApplication where a Func is used?
public string Password
{
get
{
return (this.PasswordAccessor == null) ? string.Empty : this.PasswordAccessor();
}
set
{
this.ValidateProperty("Password", value);
// Do not store the password in a private field as it should not be stored in memory in plain-text.
// Instead, the supplied PasswordAccessor serves as the backing store for the value.
this.RaisePropertyChanged("Password");
}
}
/// <summary>
/// Gets or sets a function that returns the password.
/// </summary>
internal Func<string> PasswordAccessor { get; set; }

How do you call identically named properties on different types which don't share an interface?

I have a DataTemplate that needs to set the IsSelected property on an ItemsControl's container (such as TreeViewItem, ListViewItem or ComboBoxItem). However, it doesn't know the type of the container until it's passed in to it. Since IsSelected isn't part of a common base class or interface, nor is it a common dependency property registered with AddOwner to the various classes (Duh, MS!!! WTF not?!!), I ended up with this mess...
if (container is TreeViewItem) {
(container as TreeViewItem).IsSelected = true;
return;
}
if (container is ListBoxItem) {
(container as ListBoxItem).IsSelected = true;
return;
}
if (container is ComboBoxItem) {
(container as ComboBoxItem).IsSelected = true;
return;
}
...which not only is verbose, but requires me to modify it if I ever use a different ItemsControl that uses different container types! Not good!
Sure I could enhance it a little by putting this logic in extension methods (damn C# for not having extension properties!!) called IsContainerSelected and SetContainerSelected and putting them on UIElement, then moving the above code inside there, but it's just making the outside neater. The inside is still a mess.
My only other thought is to use reflection and look for an IsSelected property and use that if found, but I'm always leery of doing things like that. However, since there isn't a common interface or base class, I'm not really sure I have a choice here.
For context, I'm sharing a complex data template between several different ItemsControls and the template itself has controls that can receive focus such as checkbox and textbox. However, when those controls receive focus via the mouse, the underlying container item doesn't get selected and whatever was selected before remains so.
My workaround is to use an attached behavior that utilizes the preview events to intercept the focus before it happens and set the underlying item accordingly, which works great when I've hard-coded TreeViewItem or ListBoxItem, etc., but I don't want to hard-code the type since the control shouldn't really care. So that's the part that breaks down.
Ugh!!! Why didn't MS just register the same attached property or at least create an ISelectableContainer interface?!!
I have read your answer, and it does make sense - in your case, IsSelected may obviously be part of the ViewModel, and that seems to be the best solution in your case.
But you asked for further explanation about C# dynamic features. C# 4.0 now has some dynamic functionalities, which allow us to create code that would only be possible in languages like Python, Ruby or JavaScript. This, of course, has its cost - a dynamic abuse would not only make code slower, but also more confusing - because you would lose compile-time errors and IntelliSense.
I have written a simple example so you may understand it better:
public class ClassOne
{
public int SameProperty { get; set; }
}
public class ClassTwo
{
public int SameProperty { get; set; }
}
public class ClassThree
{
public string SameProperty { get; set; }
}
public partial class Form1 : Form
{
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
dynamic wrapper = new ClassOne();
wrapper.SameProperty = 5;
wrapper = new ClassTwo();
wrapper.SameProperty = 15;
wrapper = new ClassThree();
wrapper.SameProperty = "Now it is a string!";
// And now a run-time error...
wrapper.AnotherProperty = "And this won't work...";
}
}
As you can see, wrapper has no definite type whatsoever - a dynamic reference will allow any kind of method or property invocation, since the actual binding will only be made during run-time, not compile-time.
Of course, this example is very naive, but sometimes dynamic code may be useful - it is a good option to avoid explicit reflection, or to avoid long if...else statements based on type (like your snippet above).
I'm not sure that I fully understand your problem, but you could try adding an IsSelected boolean to your model and then binding that property against the Item control it's contained in. That way, you just have to worry about setting that property in the model, regardless of the container.
Per #mdm20's answer, he suggested modifying the ViewModel, which is of course normally what you want to do. However this is a purely view-related issue (keyboard navigation-related) and isn't reflected in the ViewModel at all, nor in this case should it be.
But that gave me an idea! Since I'm using a custom control to render the item in whichever items control (via its data template) it's being added to, that control naturally does have multiple instances (all of which are pointing to the same ViewModel instance), which is what I want!
Therefore, rather than adding the IsSelected to the ViewModel, I added it to the user control itself, then I just bind to that within the data template for the respective ItemsControl which I do know about. I can then set the IsSelected property in the code-behind for the user control as needed (i.e. during the preview mouse events, etc.) and the underlying ItemsControl responds appropriately! Works great and keeps the ViewModel clean since neither the model, nor the viewmodel need to know about it. The IsSelected remains purely in the UI which is where in this particular case it should be!

WPF UserControl DesignMode property (Hosted on a WinForm)

I search DesignMode boolean on a custom WPF UserControl... How correctly do I impelment it?
I have a WPF Control hosted in a WinForm. I saw that the "DesignerProperties" class does not work in such a case.
I have some logic in the constructor that throws exceptions in the design mode and want to skip that code, because I don't arrive to see a Form with my UserControl in the designer.
I tried
private static bool? _isInDesignMode;
/// <summary>
/// Gets a value indicating whether the control is in design mode
/// (running in Blend or Visual Studio).
/// </summary>
public static bool IsInDesignModeStatic
{
get
{
if (!_isInDesignMode.HasValue)
{
#if SILVERLIGHT
_isInDesignMode = DesignerProperties.IsInDesignTool;
#else
var prop = DesignerProperties.IsInDesignModeProperty;
_isInDesignMode
= (bool)DependencyPropertyDescriptor
.FromProperty(prop, typeof(FrameworkElement))
.Metadata.DefaultValue;
#endif
}
return _isInDesignMode.Value;
}
}
but this does not work :(( I see designer exceptions at "blocked" with IsInDesignModeStatic code lines...
I used this to detect DesignMode (my WPF control is defined in a Class Library).
' Exit here if in Design Mode
If Assembly.GetEntryAssembly() Is Nothing Then Exit Sub
You may be able to check Assembly.GetEntryAssembly.FullName.ToString if it is not nothing and determine where the control is being initialized from.
The DesignerProperties.IsInDesignModeProperty was returning null for me when the control was hosted in WinForms because WPF doesn't know there is a designer there.
Steve
Try this
if (DesignerProperties.GetIsInDesignMode(this/*this user control*/))
{
// Design-mode specific functionality
}

multiple windows

I set up two Windows in my WPF C# Blend project. Now what I would like to know (and I have trouble finding some clear documentation) is how to run both windows on application startup and in what way I can pass code from window to window.
Thanks
In the app.xaml file for the solution, it specifies which window to run upon startup. A quick solution to open the other one is to tack on an event handler to the startup window's Loaded event which opens the second window.
However, that's not too scalable of a solution if this is part of a larger project. Having a separate class which can open each window, then neither window needs to know about the other.
As for passing data between them, using events can offer a more loosely-coupled solution. I'd push for a more MVVM (Model-View-ViewModel) architecture, then let each of the ViewModels raise events that the other can respond to. You can declare your own subclass of EventArgs which would supply the information which needs to be passed.
Update
Sorry for the delay in response. Simply, to have one Window share data with another Window, the receiver must have a way to receive that data. Defining a public property in the receiver will allow the sender to specify the data with a simple property call. By default, a Window's controls are internal, so you can access them within the same assembly, but that's not the best way to do it.
WPF has a really rich binding infrastructure that you should be taking advantage of. Do do this, your object which is providing data to the Window needs to implement the INotifyPropertyChanged interface. This will alert the UI that data has changed, and the binding should update the target with the changed data. The MSDN page describing the interface as well as a sample implementation can be found here.
When you implement that interface, that will expose an event (PropertyChanged) which will fire when data has been changed. The object providing data to the other window can register an event handler to listen for these changes, and then it will have the updated value.
Here's an example implementation of a simple class with a FirstName and LastName property.
class FirstNameViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string firstName;
public string FirstName
{
get { return firstName; }
set
{
if(firstName == value)
return;
firstName = value;
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("FirstName"));
}
}
private string lastName;
public string LastName
{
get { return lastName; }
set
{
if(lastName == value)
return;
lastName = value;
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("LastName"));
}
}
}
You can see that there's some code duplication in here--that's often refactored into a base ViewModel class. You'll see that this exposes the PropertyChanged event. Attach an event handler to it, and in the PropertyChangedEventArgs object the handler receives, the PropertyName property will contain the name of the property that was changed (the same as the string passed to the constructor in each of the setters above). The sender parameter will be a reference to the object itself. Cast it to the correct type, and you'll have access to the properties.
Hopefully that gets you a start. I wrote a very contrived sample that I can upload somewhere if you'd like to see it. It opens 2 windows, then you can see that typing in one window causes the typed text to appear in the other one, and vice versa.
If you want to pass data between the windows you should have pointers to the other window in each window. Either that, or you could read up on using a singleton-class. This is handy if you want the windows to share settings, more than sending a lot of data between them.
http://www.yoda.arachsys.com/csharp/singleton.html

Resources