How to make a custom control compatible with errorProvider? - winforms

I have a winform custom control that looks like :
Public Class MyCustomControl
Inherits Control
Implements INotifyPropertyChanged
'Some textboxes...
private Textbox1 as textbox
private Textbox2 as textbox
private Textbox3 as textbox
'Control value
Property Value as MyCustomClass
get
'Extract some values from textboxes and return MyCustomClass (a separate custom object)
end get
Set(value As MyCustomClass)
'Set the values of the textboxes from the Value object
end Set
end Property
end class
I would like to insert this object in a winform and I would like my control to be "compatible" with errorProvider. Such that if I insert an errorProvider in the form and I call : errorProvider.SetError(MyCustomControl, "Error message"), it will show the error message on a specific text box in my custom control according to a custom logic.
Does anyone know which interface should be implemented or how to that please ?
Thanks. Cheers,

What you're trying to do would be better achieved with a UserControl, instead of inheriting directly from Control. (Having three TextBox instances inside your control is a good indication here.) In your UserControl you have a couple of options:
Add an ErrorProvider component and hook it up to each TextBox; or
For each TextBox expose it by making it public or via a public property, and then in your form hook it up to the form's ErrorProvider.
Ideally, you would use a BindingSource and data bind each TextBox, with the ErrorProvider.DataSource being set to your BindingSource.

Related

Hide a property from an observablecollection

So I have a WPF DataGrid bound to an ObservableCollection, which contains a single instance of a class - for example:
Public Class parent
Public Property title As String [...]
Public Property someCommonThing as Integer [...]
Public Class Child Inherits Parent
Public Property name As String [...]
Public Property address As String [...]
Public Class Window1
Dim oc As ObservableCollection(Of Object) = New ObservableCollection(Of Object)
oc.Add(New Child())
dataGrid.ItemsSource = oc
there are many child classes with different properties, hence why I can't easily define the datagrid columns directly.
I want to be able to hide certain parent properties from the datagrid (for example, never show the title property in the datagrid), while still being able to use it for databinding elsewhere (e.g. a label).
Is this possible? I can't think how to do it without manually specifying every column for every possible class instead of using the databinding.
When automatically generating columns you can change the per-property behavior using Data Annotations, in this case specifically the BrowsableAttribute class:
<Browsable(False)>
Annotating your property with this will prevent a column from being generated when using the following event handler on the AutoGeneratingColumn event of the DataGrid.
Private Sub OnAutoGeneratingColumn(sender As Object, e As DataGridAutoGeneratingColumnEventArgs)
If Not DirectCast(e.PropertyDescriptor, PropertyDescriptor).IsBrowsable Then
e.Cancel = True
End If
End Sub
Remember to add the DataAnnotations assembly to your project.

Commands that act on two controls

Looking through the standard WPF commands, such as copy/paste, they seem to all work using one button and act on a textbox.
My question: how do I use commands when I have one button, but I need data to be set in two separate controls(a textbox and a combobox). If the user has written text in textbox, but not selected a combobox value, then CanExecute should fail. This applies if combobox has been set, but not the textbox.
In my case specifically, all these controls are wrapped in a tabitem. As well, I have another tab with only a textbox and a button. I want it to have the same functionality as the first tab, except, instead of checking for the combobox value, it should detect that there is no combobox and pass in a default 'null object' value instead.
The Execute method should call a method in my viewmodel and pass in values from the combobox and textbox. As well, each tab should pass in another unique static value; i think i can handle this using commandparameter though.
How do I make this work? Do I make the parent tab that commandtarget and directly reference its children controls in the can/execute methods?
You need to implement CanExecute method that checks both TextBox databinding value and ComboBox.SelectedItem databinding value.
Take example from your question.
Your TextBox.Text should be databinding to your ViewModel
And as well as your ComboBox.
So your ViewModel should have two Properties:
public string TextBoxCurrentText {get { ...}set {...}}
public string ComboBoxCurrentSelected {get { ...}set {...}}
Then in both Setter, you would do your YourCommmand.RaiseCanExecuteChanged();
So it will execute your CanExecute code piece to determines can your Button be click.
Which can be:
bool YourCommandCanExecute()
{
//Just example
if (!string.IsNullOrEmpty(TextBoxCurrentText) && !string.IsNullOrEmpty(ComboBoxCurrentSelected))
return true;
return false;
}

Basic WPF question: How to add a custom property trigger?

I am using Expresion Blend 3 and created a new user control in my project. I want a storyboard to run if a custom property of that user control is triggered like with the ones shown here in the list..
I learnt you need a dependency property, but my understanding there is limited. Here's the basic code I set up with property "IsAwesome" as an example..
Partial Public Class simpleControl
Public Sub New()
MyBase.New()
Me.InitializeComponent()
End Sub
Public Shared ReadOnly IsAwesomeProperty As DependencyProperty = _
DependencyProperty.Register("IsAwesome", GetType(Boolean), GetType(simpleControl))
Public Property IsAwesome() As Boolean
Get
Return DirectCast(Me.GetValue(IsAwesomeProperty), Boolean)
End Get
Set(ByVal value As Boolean)
Me.SetValue(IsAwesomeProperty, value)
End Set
End Property
End Class
However, my property doesn't show in that list. What am I missing? Or is my entire approach wrong?
Any help or advice would be appreciated!
Cheers
I created a new Wpf project. Added a new UserControl (UserControl1) with a custom dependency property called Foo.
Then I opened Blend and added an instance of UserControl1 to Window1. I right clicked on UserControl1 and said EditTemplate | Edit a Copy.
This created a copy of my user control template in the Window.Resources. From within this new template I went up to the Triggers panel and clicked the button to add a new property trigger.
Right away Blend defaulted to selecting my property in the "Activated When" section.
alt text http://blog.BradCunningham.net/Images/ForumImages/CustomDPInBlend.png
You can grab my little sample app from here: http://blog.BradCunningham.net/SourceCode/ForumSamples/CustomDPInBlend.zip

WinForms Events for Inheriting Controls for UI Style

Follow up to this question:
Winforms Style / UI Look and Feel Tips
So I have created my "base controls" from which other controls inherit from. For testing, I am trying to change one of the base label's font. But it is not propagating to the controls that inherit from it. On one of the forms, I can see the designer file is setting the properties for the control, so my base control's properties are getting overridden.
On the base control's I am using the Constructor to set the default properties. Should I be using a different event? If so, which one.
Here is the code for one of the base controls based on comment request...
Public Class InfoLabel
Inherits Label
Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.Font = New System.Drawing.Font("Tahoma", 14.25!)
Me.ForeColor = System.Drawing.Color.FromArgb(CType(CType(49, Byte), Integer), CType(CType(97, Byte), Integer), CType(CType(156, Byte), Integer))
Me.AutoSize = False
End Sub
End Class
The base controls show on the projects toolbox on the winform editor. Controls are then drag/drop from the toolbox.
Your problem is your custom control's InitializeComponent() method. I have no idea why that is there. You would get that method automatically if you were implementing a UserControl, but inheriting from a standard control that method should not be there. With your base class having an InitializeComponent() method and your subclass also having one, someone is overwriting someone else.
I just subclassed a label in C#. I dragged this on my form and the font displayed as the new font, not the base (Label) class's font.
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public class MyLabel : Label
{
public MyLabel()
{
Font = new Font("Candara", 14);
}
}
}
I then created a second label, called MySubLabel which inherited from the MyLabel class. When I changed the ForeColor on the MyLabel class, the MySubLabel automatically updated.
So this should work.
Caveat: in Visual Studio you need to recompile the assembly before trying to see updates in the designer.

How do I make the IsEnabled property of a button dependent on the presence of data in other controls? (WPF)

I have a "Login" button that I want to be disabled until 3 text boxes on the same WPF form are populated with text (user, password, server).
I have a backing object with a boolean property called IsLoginEnabled which returns True if and only if all 3 controls have data. However, when should I be checking this property? Should it be on the LostFocus event of each of the 3 dependent controls?
Thanks!
vg1890
I'd get the "backing object" to raise the IsLoginEnabled changed event when any of the 3 fields are updated. You can then bind the button to the IsLoginEnabled property and not have to keep checking it.
The pseudocode would look something like this:
Public Event IsLoginEnabledChanged As EventHandler
Public Property User() As String
Get.. ' snipped for brevity
Set(ByVal value As String)
mUser = value
RaiseEvent IsLoginEnabledChanged(Me, New EventArgs())
End Set
' do the same in the Set for Password() and Server() properties
The trick to this is naming the Event [PropertyName]Changed (i.e. IsLogonEnabledChanged) - because raising this event will automagically notify any bound controls :o)
Yes, I would say the easiest option would be to check it on the LostFocus or TextChanged event of each of those controls. However, if you want to do a little heavier lifting, you could implement the boolean as a dependency property that you could have bound to the button's Enable.
http://msdn.microsoft.com/en-us/library/ms750428.aspx
Can you just databind your IsLoginEnabled right to the Enabled property of the login button?
I think you could use RoutedCommands one of the most useful features of WPF. Basically add a CommandBinding, to use OnExecute and OnQueryCommandEnabled to manage button's enabled state.
Check out this wonderful explanation on using RoutedCommands in WPF

Resources