1
votes

I know this question is probably going to get alot of "Duplicate question" comments but i have yet to see one with an answer that works or isn't simply "Avoid it at all cost". But here goes, i have created a control lets call it "ControlA" in a project called "ControlA_Project" and i was intending to override some of its virtual methods in a control called "ControlB" that inherites "ControlA" in another project called "ControlB_Project" . The idea being that "ControlA" has save and load methods that i wish to change from saving and loading to file, too saving and loading to database ( and if later on another save and load type is required i can just override those methods again ). The problem i have is i originally had "ControlA" as a usercontrol and when i tried adding the new control with the overrides ("ControlB") into a window i would get this error:

The component 'ControlB_Project.ControlB' does not have a resource identified by the URI '/ControlA_Project;component/usercontrols/ControlA.xaml'.

Googling the error i came to the conclusion you could not inherit from a user control ( or for the sake of arguement it wasn't a good idea ). So i then changed the control from a user control to a custom control. this however then leads me to another problem, a template for a control doesnt link to the code behind (i.e On_Click) like it does in a user control and there is no easy way to simply override the behavier (as far as i am aware). I know i can retemplate ControlB by copy and pasting ControlAs template and changing a few lines but controlA has a large template as it is and making mutliple copies seems a waste of space. So put simply is there a correct way to change the behavier of a control in wpf?

1
Sorry to say but you are doing it so wrong. YOu are mixing LOGIC with UI. To quote you "The idea being that "ControlA" has save and load methods that i wish to change from saving and loading to file, too saving and loading to database". Your problem lies in a wrong architecture, and would not be existent if the UI would not do logic. WPF does not like this approach. Google MVVM or DataBinding for example.Marino Šimić
I'm with Marino on this one. And if the storage strategy is the only thing differentiates Control A and B, why not pull it out into its own class and keep just one control? In ControlA_Project, you give it the file storage class, and in the B project, you give it a db implementation.Vegar
Just a suggestion -- WPF really shines when you let the UI layer focus on presenting data and you move the data and logic layer out of the UI and into dedicated classes. Like others have said, I would recommend looking at the Model-View-ViewModel (MVVM) patterncordialgerm
Don't get me wrong i have used wpf in the correct way for some other controls, controlA was infact the editor for the other controls. although the other controls where designed to be look-less, i had no intention of making the editor look any different and thats where i got myself into a bind. I started thinking of the editor as a form instead of a control and it probably should be but i wanted to keep it all together in a neat dll.E.L Dunn

1 Answers

2
votes

First, remember that the ControlTemplate can be changed by the user alot so you need to make sure that important fields are clearly marked. So if you want an OnClick event. First mark your button as "important"

<Button x:Name="PART_MyButton"/>

Its also a good idea to mark this aswell on your control class

[TemplatePart(Name = "PART_MyButton", Type = typeof(Button))]
public class MyCustomControl : Control

Now you want to attach to the on click event of that button to do that, override the OnApplyTemplate method.

public override void OnApplyTemplate()
{
    mButton = Template.FindName("PART_MyButton", this) as Button;
    mButton.Click += MyEventHandler;
}

Depending on how well your control can work without the control, you should gracefully handle a not found control or throw an exception.

One final thing is. If you override a control which has a default style, it might be a good idea to provide a new default style.

static MyCustomControl()
{
    DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new FrameworkPropertyMetadata(typeof(MyCustomControl)));
}

and placing an implicit style in your generic.xaml