Search code examples
wpfmvvmdatatemplatecode-behindresourcedictionary

Code-behind for DataTemplate in a ResourceDictionary


I am attempting to use code-behind to support an event handler in a DataTemplate. The below code works fine when it is the code-behind for a Window, but not for a ResourceDictionary. The code will not even compile when put in the code-behind for the ResourceDictionary.

I know that Commands is the better option here, but this is largely a test to make sure I can handle events on resources in a ResourceDictionary, if needed. My goal is to better organize my code, but this is not the straightforward "include" behavior that I thought a separate ResourceDictionary file would provide.

In MainWindow.xaml:

    <Window x:Class="Wizbang.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:DevComponents.WpfEditors;assembly=DevComponents.WpfEditors"
        xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
        xmlns:local ="clr-namespace:Wizbang"
        xmlns:m ="clr-namespace:Wizbang.Model"
        xmlns:vm="clr-namespace:Wizbang.ViewModel"
        xmlns:vw="clr-namespace:Wizbang.View"
        DataContext="{Binding Path=Main, Source={StaticResource Locator}}"
        Title="Wizbang" Height="760" Width="1335" WindowStartupLocation="CenterScreen">

        <Window.Resources>
            <ResourceDictionary>
                 <ResourceDictionary Source="Resources/MainWindowResources.xaml" />
            </ResourceDictionary>
        </Window.Resources>

In code-behind MainWindow.xaml.cs and MainWindowResources.xaml.cs, the same code:

private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            //switch item template
            Button btn = (Button)sender;
            //command contains the list item
            ContentControl itm = (ContentControl)btn.CommandParameter;

            itm.SetValue(ContentTemplateProperty, this.FindResource("DetailedTemplate") as DataTemplate);

            //this.UpdateLayout();

        }

When I keep the ResourceDictionary inline in MainWindow.xaml, and put the code-behind in MainWindow.xaml.cs, everything works. When I attempt to use a separate file for ResourceDictionary, the code does not compile. The compiler complains about the last line:

itm.SetValue(ContentTemplateProperty, this.FindResource("DetailedTemplate") as DataTemplate);

The this.FindResource() is not a valid method, and "ContentTemplateProperty" is not found:

Error 4 The name 'ContentTemplateProperty' does not exist in the current context C:...\Visual Studio 2010\Projects\Wizbang\Wizbang\Resources\MainWindowResources.xaml.cs 36 26 Wizbang

Error 5 'Wizbang.Resources.MainWindowResources' does not contain a definition for 'FindResource' and no extension method 'FindResource' accepting a first argument of type 'Wizbang.Resources.MainWindowResources' could be found (are you missing a using directive or an assembly reference?) C:...\Visual Studio 2010\Projects\Wizbang\Wizbang\Resources\MainWindowResources.xaml.cs 36 56 Wizbang

If I remove that last line, the code compiles and runs, but the button has no functionality. I think my issue is mapping that last line's references from the perspective of a ResourceDictionary, but I am not sure why it should be different.

Thanks for any thoughts.

Bill


Solution

  • This is because the code no longer is in the window class. You have to find it again (or whatever control you want to place the template on).

    Window parentWindow = Window.GetWindow(btn);
    itm.SetValue(Window.ContentTemplateProperty, parentWindow.FindResource("DetailedTemplate") as DataTemplate);