Visual Basic .NET Forums  
Click here to advertise with us

Go Back   Visual Basic .NET Forums > Visual Studio .NET > Windows Presentation Foundation (WPF)

VB.NET Forums Newsletter Signup:
Email address:


Reply
 
LinkBack Thread Tools Display Modes
  #1 (permalink)  
Old 02-08-2010, 4:32 PM
VB.NET Forum Newbie
.NET Framework: .NET 4.0
 
Join Date: Dec 2009
Age: 27
Posts: 12
Reputation: 6
muik is on a distinguished programming path ahead
Default Expose properties from an element that is inside a UserControl?

Hi,

I have created the following UserControl (simplified to the bare minimum for clarity):

<UserControl x:Class="StealthComboBox">
<Grid>
<Label Name="lblHeader" />
<Label Name="lblcboBoxValue" />
<ComboBox Name="cboBox" />
</Grid>
</UserControl>

I would like the users of my UserControl to be able to add items to the ComboBox through code.

I have tried a few things already by adding code to the StealthComboBox class, here are 2 examples:


Public Items as ItemCollection = cboBox.Items
Even though the UserControl builds fine, trying to add it to a project gives me the error "Could not create an instance of type:StealthComboBox"

Public DropDownList as ComboBox = cboBox
The UserControl builds fine and I could add it to my project - it displays fine and Intellisense shows the ComboBox properties fine. However the "DropDownList" item is actually "Nothing": it does not reference to the cboBox inside my UserControl and any attempt to use it gives an NullReferenceException.

Is there a simple way to directly expose the ".Items" and ".SelectedItem" properties and methods in a UserControl? I know that I can create home-made functions in my "StealthComboBox" class that will query the ComboBox values or use its .Items.Add function, like this:

Public Function Add(obj_ as Object) as Integer
Return cboBox.Items.Add(_obj)
End Function

Public Function SelectedItem() as Object
Return cboBox.SelectedItem()
End Function

This works pretty well, actually. But I'm mostly wondering if there's a more conventional way - one that would give my UserControl the full interface of a ComboBox instead of me "handpicking" the ones I think I will need?

And a more advanced question: what if I want a UserControl with 2 ComboBox items that must be exposed to the user? Isn't there a way to create some kind of "UserControl.List1" and "UserControl.List2", where each of them acts on a separate ComboBox list? (i.e. UserControl.List1.Items.Add and UserControl.List2.Items.Add)

Thanks for the help!
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #2 (permalink)  
Old 02-08-2010, 8:52 PM
JuggaloBrotha's Avatar
VB.NET Forum Moderator
.NET Framework: .NET 3.5 (VS 2008)
 
Join Date: Jun 2004
Location: Lansing, MI; USA
Age: 25
Posts: 3,631
Reputation: 396
JuggaloBrotha master of VB.NETJuggaloBrotha master of VB.NETJuggaloBrotha master of VB.NETJuggaloBrotha master of VB.NETJuggaloBrotha master of VB.NETJuggaloBrotha master of VB.NETJuggaloBrotha master of VB.NETJuggaloBrotha master of VB.NETJuggaloBrotha master of VB.NET
Default

To expose the Items collection you have to do something along these lines:
Code:
Public Property Items() As ObjectCollection
  Get
    Return ComboBox.Items
  End Get
  Set (ByVal Value As ObjectCollection
    ComboBox.Items = ObjectCollection
  End Set
End Property
And to give the user access to the SelectedItem your code's correct:
Code:
Public Function SelectedItem() as Object

    Return cboBox.SelectedItem()

End Function
__________________
Currently using: VS 2005 & 2008 Pro w/sp1 on Win7 Ultimate x64.


There are 3 kinds of people in the world: Those who can count and those who can't.
4 out of 3 people have trouble with fractions.

Windows has a 64 bit GUI for a set of 32 bit extensions on a 16 bit shell for an 8 bit OS using a 4 bit kernel made by a 2 bit company that can't stand 1 bit of competition.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #3 (permalink)  
Old 02-09-2010, 7:18 AM
JohnH's Avatar
VB.NET Forum Moderator
.NET Framework: .NET 3.5 (VS 2008)
 
Join Date: Dec 2005
Location: Norway
Age: 37
Posts: 10,322
Reputation: 1315
JohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond repute
Default

If you don't want to change the functionality mirroring those properties is usually what you do. That means using the same signature and get/set the internal objects property. Take for example Items property, when you look it up in help you get this page (this property is inherited from ItemsControl class) ItemsControl.Items Property (System.Windows.Controls) At top of page you see the declaration:
Code:
<BindableAttribute(True)> _
Public ReadOnly Property Items() As ItemCollection
If you paste this and press Enter you get the full property body:
Code:
<BindableAttribute(True)> _
Public ReadOnly Property Items() As ItemCollection
    Get

    End Get
End Property
Then you fill in the code to get the items from the internal Combobox control:
Code:
Return CB.Items
__________________
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #4 (permalink)  
Old 02-09-2010, 10:37 AM
VB.NET Forum Newbie
.NET Framework: .NET 4.0
 
Join Date: Dec 2009
Age: 27
Posts: 12
Reputation: 6
muik is on a distinguished programming path ahead
Default

Thanks for the quick replies!

However, none of your suggestions will retain the full functionalities of the ComboBox. It does work fine and having the ObjectCollection exposed is better functionality than a single link to the .Add method, and is enough for what I need to do (but so was my original code). Imagine a DataGrid - you will want to keep a LOT of the features it has and you probably don't want to relink everything manually...

I thought of something overnight though, and I just tried it and it works perfectly. It also answers my "what if you need 2 ComboBox to retain full functionality" question.

Basically, i was very close when I exposed a public variable that would link to my cboBox:

Code:
Class StealthComboBox
    Public myBox as ComboBox = cboBox
End Class
For some reason, the above code builds correctly but gives a "NullReferenceException" when trying to access the myBox reference.

By changing the variable to a readonly property (this is what i dreamed about last night...):

Code:
Class StealthComboBox
    Public Readonly Property myBox() As ComboBox
        Get
            Return cboBox
        End Get
    End Property
End Class
...not only it still builds correctly, but accessing to ".myBox" exposes the whole ComboBox members. They retain full functionality and even though the ".myBox" reference is readonly (which is what i want, obviously), any property within the ComboBox retains their original read/write settings.

If I would create a UserControl with, let's say, 2 ComboBox: one with Country and the other one with State, the easiest way to let the code access both of them would be:

Code:
(XAML)
<UserControl Name="CountryStateSelector">
    <Grid>
        <ComboBox Name="_CountrySelector" />
        <ComboBox Name="_StateSelector" />
    </Grid>
</UserControl>

(Code-Behind)
Class CountryStateSelector
    Public Readonly Property CountrySelector() as ComboBox
        Get
            Return _CountrySelector
        End Get
    End Property

    Public Readonly Property StateSelector() as ComboBox
        Get
            Return _StateSelector
        End Get
    End Property
End Class
Then in my application:

Code:
(XAML)
<my:CountryStateSelector Name="LocationSelector" />

(Code-Behind)

Public Sub somesub()
    LocationSelector.CountrySelector.Items.Add("USA")
    LocationSelector.CountrySelector.Items.Add("Canada")
    LocationSelector.StateSelector.Items.Add("Boston")
    LocationSelector.StateSelector.Items.Add("Quebec")
End Sub
Now I can access the whole combobox features with very minimal code.

The only drawback of this approach is that the combo box still isn't reachable through XAML so I can't use databinding. But for what I need to do, this is sufficient. I guess I could easily map a bindable property to the objectcollection afterward if i need databinding.

yay!
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #5 (permalink)  
Old 02-09-2010, 6:39 PM
JohnH's Avatar
VB.NET Forum Moderator
.NET Framework: .NET 3.5 (VS 2008)
 
Join Date: Dec 2005
Location: Norway
Age: 37
Posts: 10,322
Reputation: 1315
JohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond repute
Default

That combobox is already exposed in that fashion (Friend access level); you can write LocationSelector.cboBox to access it. This actually something one usually want to avoid to protect the internal objects, and outside assembly it is. More so exposing properties on the UserControl itself allow Designer support, you can for example set the usercontrol Items in Designer with the property I posted. From what I see that is also possible by exposing the control as regular property (not ReadOnly) in WPF, then you get a sublevel in Properties window for all the internal controls properties, IMO this is not desirable. Designer/Design-time support is of great importance and should be a main consideration when developing custom controls for a visual development environment.
__________________
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #6 (permalink)  
Old 02-10-2010, 11:08 AM
VB.NET Forum Newbie
.NET Framework: .NET 4.0
 
Join Date: Dec 2009
Age: 27
Posts: 12
Reputation: 6
muik is on a distinguished programming path ahead
Default

Quote:
Originally Posted by JohnH View Post
That combobox is already exposed in that fashion (Friend access level); you can write LocationSelector.cboBox to access it. This actually something one usually want to avoid to protect the internal objects, and outside assembly it is.
I cannot seem to access cboBox from an application that references to my UserControl if I don't declare it public within my UserControl project. So "LocationSelector.cboBox" is not something that can be accessed if I don't specifically create a public that ties to it - am I missing something?

For the rest, I agree that your approach seems more conventional and probably more useful for designers. However for the sake of these usercontrols, it's not meant to be distributed and I'm the designer - they're mainly just a way for me to quickly place elements that are redundant in my application in an effort to lighten my XAML code that was beginning to be hard to maintain due to a "Tabs" apporoach.

Thanks a lot for the help and explanations - I have a better understanding of its mechanics now and the info could definitely be useful on future projects.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #7 (permalink)  
Old 02-10-2010, 1:42 PM
JohnH's Avatar
VB.NET Forum Moderator
.NET Framework: .NET 3.5 (VS 2008)
 
Join Date: Dec 2005
Location: Norway
Age: 37
Posts: 10,322
Reputation: 1315
JohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond reputeJohnH has a reputation beyond repute
Default

Quote:
I cannot seem to access cboBox from an application that references to my UserControl if I don't declare it public within my UserControl project. So "LocationSelector.cboBox" is not something that can be accessed if I don't specifically create a public that ties to it - am I missing something?
That was what I said. Assembly is a compiled application or library.

As the developer everything is your choice, but in case you misinterpreted this; "Designer" is visual part in IDE, as in "View Designer"
__________________
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #8 (permalink)  
Old 02-10-2010, 1:48 PM
VB.NET Forum Newbie
.NET Framework: .NET 4.0
 
Join Date: Dec 2009
Age: 27
Posts: 12
Reputation: 6
muik is on a distinguished programming path ahead
Default

/facepalm @ "I'm the designer!"

Got it. Thanks for the clarification
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply

Bookmarks


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On





All times are GMT -4. The time now is 8:10 PM.

Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.2


For advertising opportunities click here.