134

Is it possible to set code behind a resource dictionary in WPF. For example in a usercontrol for a button you declare it in XAML. The event handling code for the button click is done in the code file behind the control. If I was to create a data template with a button how can I write the event handler code for it's button click within the resource dictionary.


  • The correct way to do this is to use a command, it also gives you the ability to enable and disable the button, while you can do it the way some answers have suggested it smells to me of a hack. - Aran Mulholland

4 답변


195

I think what you're asking is you want a code-behind file for a ResourceDictionary. You can totally do this! In fact, you do it the same way as for a Window:

Say you have a ResourceDictionary called MyResourceDictionary. In your MyResourceDictionary.xaml file, put the x:Class attribute in the root element, like so:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    x:Class="MyCompany.MyProject.MyResourceDictionary"
                    x:ClassModifier="public">

Then, create a code behind file called MyResourceDictionary.xaml.cs with the following declaration:

namespace MyCompany.MyProject
{
    partial class MyResourceDictionary : ResourceDictionary
    { 
       public MyResourceDictionary()
       {
          InitializeComponent();
       }     
       ... // event handlers ahead..
    }
}

And you're done. You can put whatever you wish in the code behind: methods, properties and event handlers.

== Update for Windows 10 apps ==

And just in case you are playing with UWP there is one more thing to be aware of:

<Application x:Class="SampleProject.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:rd="using:MyCompany.MyProject">
<!-- no need in x:ClassModifier="public" in the header above -->

    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>

                <!-- This will NOT work -->
                <!-- <ResourceDictionary Source="/MyResourceDictionary.xaml" />-->

                <!-- Create instance of your custom dictionary instead of the above source reference -->
                <rd:MyResourceDictionary />

            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>

</Application>


  • As an addendum to ageektrapped's answer: Make sure that you put the fully qualified name of your codebehind class in the x:Class attribute. x:Class="MyCompany.MyProject.MySubFolder1.MyResourceDictionary" Otherwise, if you merely put x:Class="MyResourceDictionary", the xaml parser won't find your class. - viggity
  • Make sure you provide a default constructor in the partial class codebehind, and make sure it calls InitializeComponent(). (In my case I was using MEF to Export the resource dictionary.) - Scott Whitlock
  • Updated code snippet for upvoted comment. I felt it was needed to complete the answer ; a common mistake. I did it just now :) Revert if you dont like it. Thanks for the answer. - Gishu
  • Note that (at least in wp8.1) this is no longer valid and you'd have to create a custom usercontrol that your resourcedictionary references - Jared
  • You'll also have to set the Build Action on the ResourceDictionary's XAML file to "Page", otherwise the InitializeComponent() call won't compile. (ResourceDictionary XAML files are usually set to "Resource" by default.) - user1454265

9

I disagree with "ageektrapped"... using the method of a partial class is not a good practice. What would be the purpose of separating the Dictionary from the page then?

From a code-behind, you can access a x:Name element by using:

Button myButton = this.GetTemplateChild("ButtonName") as Button;
if(myButton != null){
   ...
}

You can do this in the OnApplyTemplate method if you want to hookup to controls when your custom control loads. OnApplyTemplate needs to be overridden to do this. This is a common practice and allows your style to stay disconnected from the control. (The style should not depend on the control, but the control should depend on having a style).


  • Phobis I think the purpose of separating the Dictionary from the page is about reusability and readability of the Main page xaml. The above solution worked for me too. - cleftheris

5

Gishu - whilst this might seem to be a "generally not to be encouraged practice" Here is one reason you might want to do it:

The standard behaviour for text boxes when they get focus is for the caret to be placed at the same position that it was when the control lost focus. If you would prefer throughout your application that when the user tabs to any textbox that the whole content of the textbox was highlighted then adding a simple handler in the resource dictionary would do the trick.

Any other reason where you want the default user interaction behaviour to be different from the out of the box behaviour seems like good candidates for a code behind in a resource dictionary.

Totally agree that anything which is application functionality specific ought not be in a code behind of a resource dictionary.


0

XAML is for constructing object graphs not containing code.
A Data template is used to indicate how a custom user-object is to be rendered on screen... (e.g. if it is a listbox item) behavior is not part of a data template's area of expertise. Redraw the solution...


  • conclusion: Would u recommend on using resource dic with code behind or not?? I have never used it, I am doubting. - Shimmy
  • I wouldn't - to me it doesnt feel right. A dictionary should return values for specific keys. In the OP's case, bundling code with the data template.. I'd rather try a different approach.. use the Command model for instance. I need more details on the OP's problem to recommend a diff soln. - Gishu
  • Completely disagree. With MVVM, there is one scenario where having code behind is extremely useful: developing attached properties. Get it working with code behind, then port it to an attached property. This is much faster than simply developing the attached property from scratch, unless you have a brain the size of Manhattan. - Contango

Linked


Related

Latest