How to expose xaml properties? - wpf

I created a ComboBox subclass and added my functionality.
Now I want to expose external properties of the TextBox for example:
<a:MyComboBox SpellCheck.IsEnabled="True" TextBox.SelectedText="{Binding X}" />
Is this possible, I maybe didn't choose the wrong particular property but I guess you understand what I mean.
Is this possible?
Do I have to create all the properties individually?

This is not possible in XAML. XAML does not allow you to address sub-properties of individual members using a property path syntax like the one you describe. (Something similar is possible for certain inheritable properties such as backgrounds and font sizes, but that uses an inheritance mechanism -- affecting all contained controls -- rather than addressing a specific sub-element, and wouldn't work for TextBox.SelectedText anyway.)
So yes, you will need to declare custom properties on the MyComboBox class to surface the features of the TextBox that you need to access from outside the MyComboBox. On the plus side, this is good discipline for encapsulation: remember that a future developer might apply a custom template to your MyComboBox that doesn't include a TextBox (or the member isn't named TextBox, or the member named TextBox is actually a RichTextEditor instead of a plain TextBox...). Explicit properties ensure that MyComboBox defines clearly what behaviour and state such a template needs to respect, and lets the template decide how to implement that, rather than the author of the template being constrained always to expose a TextBox.

Related

Extending a subelement within a ControlTemplate

I’m trying to extend an Expander’s header (the ToggleButton part) to allow for some more custom features. Being rather new to extending WPF controls using ControlTemplates, I have already accepted by now, that I will have to completely replace the Expander’s template by my own (without being able to reuse originally defined components, or even styles, which makes this quite a bit annoying in my opinion – but that’s not what the question is about).
However, I wanted to introduce some properties which change the way the component looks and works. So I created a new subtype of Expander which simply defines the new dependency properties I want to use. But I noticed that, given that I want to use those properties within the template for the ToggleButton, which is nested inside of the one for the Expander, I cannot use those properties like that. So I had to subtype ToggleButton too, define the dependency properties for that type as well, and make the Expander’s template pass the values through to the ToggleButton template.
So I ended up with two new types in the namespace (nesting the new ToggleButton type inside of the Expander subtype didn’t work?), a complete copy of the Expander’s template with only a single line changed (where the ToggleButton was inserted, passing through the new properties), and then the actual desired changes for the ToggleButton template.
And here comes the question: Is there any way to make this less complicated? To reduce the amount of work that needs to be done just for extending a subcomponent of another’s template? Or just a way to use the parent’s (Expander) properties inside of the ToggleButton template without having to subtype that one as well?
I ended up using what jberger suggested in the comments:
Using the following binding expression I did not need to duplicate the DependencyProperties into another component for the ToggleButton, but could just access the Expander’s properties inside the nested template:
{Binding CustomProperty, RelativeSource={RelativeSource
FindAncestor, AncestorType=local:CustomExpander}}
Sadly, but as expected, one apparently cannot reuse template parts from the default. However in this case I could leave out parts from the original template that I didn’t need in my copy. For example the different styles for non-default expanding (i.e. other than Top), as my expander is specialized to that layout.
This however rendered the ExpandDirection property useless, but I personally can accept that. It might lead to a follow-up question though; if one should rather build the component from scratch (based on Expander’s base, instead of Expander itself).

Extending user controls in WPF

I have built a User Control composed, as usual, of a XAML part and a code-behind part. Now, I need to create another User Control which shares some of the functionalities of the former, but which has different looks and might also have additional features in the code-behind.
My first idea was to create an interface to gather the common functionalities of the two types of controls. Is this the right way to go? And how would I manage the different XAML parts I should have? Any advice is welcome.
I would like to add another contribution which I think might be useful to others encountering my same situation.
One other possible solution, which in my opinion is suitable if the controls you are going to create are not particularly complex, is to create a base User Control containing the common features that you want to share: such control will be written entirely in C#.
This, in fact, allows inheritance in User Controls composed of both XAML and code behind. In the XAML of the inherited control, rather than having
<UserControl> ... </UserControl>
You will have
<MyProject: MyBaseControl x:Class="MyProject.MyExtendedControl"> ... </MyProject: MyBaseControl>
and then in the code behind you will also need to specify the following:
class MyExtendedControl : MyBaseControl
Hope this helps.
User controls don't lend themselves well to inheritance in WPF, you can do some hacks to make it work, but overall you'll probably be better off using a Custom Control instead. It's easier to specify different XAML for inherited controls using this technique. The easiest way to get started with a custom control is to add a new item to your project of type "Custom Control (WPF)" and it will add the control and the XAML gets added to Themes/generic.xaml for you.
To inherit from this control, the easiest way is to add another new Custom Control (WPF) and then change the code behind to inherit from your parent control instead of Control.
There are a number of ways to split up the pieces to make them easier to work with.
MVVM, as mentioned in a comment, relies upon Data Binding to separate the input controls from logic. By setting the appropriate class which implements INotifyPropertyChanged into the DataContext of you control, you can change the behaviour. Your DataContext class or ViewModel could implement Visibility properties to show and hide different parts of the input if the differences are not too great between the uses.
Another way to break apart functionality is by Aggregation. See StackOverflow 269496
You could build smaller controls that implement common functionality and then build larger special purpose controls by combining the smaller controls (i.e. aggregating them) to make the larger control. Aggregation will work for both the code-behind and the Data Binding approaches.

viewmodel have to be public. How should I deal with that?

Pretty much it summarizes my problem here:
Double check - does it ever make sense to have internal viewmodel class?
I have controls.DLL and I'd like to keep this custom control bindings and viewmodel's internal. However, this doesn't seem to be possible.
How do you get around that? The only way I see it - don't use bindings..
Why do you have a view model for a custom control? I assume you're assigning the view model object to the DataContext property, but this is almost always a mistake: the DataContext should be available to consumers to use and abuse as they please. Stated another way, what happens if a consumer of your custom control explicitly sets the DataContext? It sounds like your control will stop working and throw a bunch of xaml binding errors.
A custom control is inherently lookless. There is no model or view model, just a view. That view is the .cs file. You supply a default look via your themes/generic.xaml file, but consumers should be able to supply their own template. If you're tying them to a view model, they also need to know how to create a view model instance and all of its dependencies. You've just created highly coupled code. DI containers can loosen the coupling, but that just downgrades the relationship between classes from "coupled" to "related". I say, why do consumers even need to know that information?
A better approach is to provide all of the properties for your control as dependency properties. Then your generic.xaml can provide a control template that uses the more efficient TemplateBinding to bind properties/objects to your control. If you need to populate these dependency properties from a business object, expose another dependency property of type IBusinessObject and set the derived values in that object's PropertyMetaData changed handler. If your IBusinessObject type contains a property which is yet another class which implements INotifyPropertyChanged, you should probably (1) rethink your object graph or (2) create a Bnding object in code using the subclass.
I think following all of the above advice will eliminate the problem about which you're concerned plus the other problems as well. Leave the view models to the UserControls. And yes, this is why custom controls are a MASSIVE headache. Doing them right is fairly involved.
Try protected internal. I suppose this should work. Although I don't think its good idea to have the ViewModel not public at all, cause one of the purposes of it is to be able to define several Views against the same ViewModel, which may come from different assemblies.

Can I use different datatemplate for same datatype basedon some creteria?

I'm new to wpf and now I have a problem. I have a model class say Customer and I've created a DataTemplate with TargetType property set to Customer. It works good. But I actually want two different templates like one for just displaying the record and another for in-place editing. Is it possible to specify two different templates for same datatype based on some creteria?
And I want to switch this template based on some property on ViewModel like when IsEditmode is True.
Or am I doing it wrong? Should I use styles instead?
Your approach seems to be perfectly fine.
You can create a DataTemplateSelector which will allow you to choose a data template based on arbitrary criteria from code behind.
I often use these to decide which template to use based on a enum-type property.
There are two easy ways I can think of, ofcourse there are other ways based on the complexity and architecture you want to follow.
Define DataTemplate with 'Key' and specifically call that either using StaticResource/DynamicResource Binding.
You can have a DataTrigger inside the datatemplate which makes some parts of the template visible/collapsed based on your 'EditMode' property

WPF - Which one is better? Style or User Control?

I wanted to know which one amongst Style and UserControl would be better to use in WPF?
For example:
I have created an image button in two different ways.
One uses Style and ContentTemplate property is set.
It uses one other class with dependency properties.
The other way is I have created a UserControl which has a button and its content property is set.
The file UserControl.xaml.cs also contains the dependency properties.
For Code details see the answers of this question:
Custom button template in WPF
Which one would be better to use? In which scenario should one go for Style or UserControl or any CustomControl?
Styles are limited to setting default properties on XAML elements. For example, when I set the BorderBrush , I can specify the brush but not the width of the border. For complete freedom of a control’s appearance, use templates. To do this, create a style and specify the Template property.
Styles and templates still only allow you to change the appearance of a control. To add behavior and other features, you’ll need to create a custom control.
For example,
To create a button like a play button use styles and templates, but to create a a play button which will change its appearance after pausing it use UserControl.
For this type of thing I would go with Style, even though I'm not really adept with graphical tools. I tend to produce a basic, boring style that I can get started with and then prettify it once the application functionality has been verified.
The nicest thing about WPF is being able to distance much of the graphical look, feel and behaviour away from the code.
This allows you to change the style of your application without revisiting the code and indeed means that you can change styles on the fly at runtime.
There is an awkward line to tread with regards to how much behaviour is placed within the XAML and how much is placed within the code. A rough guide would be to decide on what behaviour must always be present within the UI and place that in the code, everything else place within the XAML.
Think of the code as being an abstract class with defined interfaces and the XAML Styles as being classes based on that class and you'll get an idea of what I mean.
Conversely, I know that people who are far more adept at the GUI work prefer to put more functionality in the XAML and others who prefer the code side, because they find the GUI work slow or difficult.
When thought of that way you'll see that there's never really a right or wrong answer, just better solutions that suit your skills.

Resources