¿Es posible establecer código detrás de un diccionario de recursos en WPF para el manejo de eventos?

147

¿Es posible establecer código detrás de un diccionario de recursos en WPF? Por ejemplo, en un control de usuario para un botón, lo declara en XAML. El código de manejo de eventos para el clic del botón se realiza en el archivo de código detrás del control. Si tuviera que crear una plantilla de datos con un botón, ¿cómo puedo escribir el código del controlador de eventos para hacer clic en el botón dentro del diccionario de recursos?

Crippeoblade
fuente
1
La forma correcta de hacerlo es usar un comando, también le permite habilitar y deshabilitar el botón, mientras que puede hacerlo de la forma en que algunas respuestas me han sugerido que huele a un truco.
Aran Mulholland

Respuestas:

209

Creo que lo que estás preguntando es si quieres un archivo de código subyacente para un ResourceDictionary. ¡Puedes hacer esto totalmente! De hecho, lo haces de la misma manera que para una ventana:

Digamos que tiene un ResourceDictionary llamado MyResourceDictionary. En su archivo MyResourceDictionary.xaml, coloque el atributo x: Class en el elemento raíz, así:

<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">

Luego, cree un código detrás del archivo llamado MyResourceDictionary.xaml.cs con la siguiente declaración:

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

Y tu estas listo. Puede poner lo que desee en el código: métodos, propiedades y controladores de eventos.

== Actualización para aplicaciones de Windows 10 ==

Y en caso de que estés jugando con UWP, hay una cosa más a tener en cuenta:

<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>
ageektrapped
fuente
77
Como un apéndice de la respuesta de ageektrapped: asegúrese de poner el nombre completo de su código detrás de la clase en el atributo x: Clase. x:Class="MyCompany.MyProject.MySubFolder1.MyResourceDictionary"De lo contrario, si simplemente coloca x: Class = "MyResourceDictionary", el analizador xaml no encontrará su clase.
viggity
29
Asegúrese de proporcionar un constructor predeterminado en el código de clase parcial detrás y asegúrese de que llame a InitializeComponent (). (En mi caso, estaba usando MEF para exportar el diccionario de recursos.)
Scott Whitlock,
44
Fragmento de código actualizado para comentarios votados. Sentí que era necesario completar la respuesta; un error común. Lo hice justo ahora :) Revertir si no te gusta. Gracias por la respuesta.
Gishu
2
Tenga en cuenta que (al menos en wp8.1) esto ya no es válido y tendría que crear un control de usuario personalizado que sus recursos de referencia referenciales
Jared
9
También deberá establecer la Acción de compilación en el archivo XAML de ResourceDictionary en "Página", de lo contrario, la llamada InitializeComponent () no se compilará. (Los archivos XAML ResourceDictionary generalmente están configurados en "Recurso" de forma predeterminada)
User1454265
9

No estoy de acuerdo con "ageektrapped" ... usar el método de una clase parcial no es una buena práctica. ¿Cuál sería el propósito de separar el Diccionario de la página entonces?

Desde un código subyacente, puede acceder al elemento ax: Name utilizando:

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

Usted puede hacer esto en el método OnApplyTemplate si quieres transmisión en circuito con los controles Una vez cargada de control personalizado. OnApplyTemplate necesita ser anulado para hacer esto. Esta es una práctica común y permite que su estilo permanezca desconectado del control. (El estilo no debe depender del control, pero el control debe depender de tener un estilo).

Phobis
fuente
77
Phobis Creo que el propósito de separar el Diccionario de la página es sobre la reutilización y la legibilidad de la página principal xaml. La solución anterior también funcionó para mí.
cleftheris 02 de
5

Gishu: si bien esto puede parecer una "práctica que generalmente no se recomienda" Aquí hay una razón por la que es posible que desee hacerlo:

El comportamiento estándar de los cuadros de texto cuando obtienen el foco es que el cursor se coloque en la misma posición que estaba cuando el control perdió el foco. Si prefiere en toda su aplicación que, cuando el usuario se dirija a cualquier cuadro de texto, se resalte todo el contenido del cuadro de texto, entonces agregar un controlador simple en el diccionario de recursos sería suficiente.

Cualquier otra razón por la que desee que el comportamiento predeterminado de interacción del usuario sea diferente del comportamiento listo para usar parece ser un buen candidato para un código detrás en un diccionario de recursos.

Totalmente de acuerdo en que cualquier cosa que sea específica de la funcionalidad de la aplicación no debe estar en un código detrás de un diccionario de recursos.

Pete Maher
fuente
0

XAML es para construir gráficos de objetos que no contienen código.
Una plantilla de datos se usa para indicar cómo se debe representar un objeto de usuario personalizado en la pantalla ... (por ejemplo, si es un elemento de cuadro de lista) el comportamiento no es parte del área de especialización de una plantilla de datos. Redibujar la solución ...

Gishu
fuente
conclusión: ¿Recomendaría usar el recurso dic con código detrás o no? Nunca lo he usado, estoy dudando.
Shimmy Weitzhandler
1
No lo haría, para mí no se siente bien. Un diccionario debe devolver valores para claves específicas. En el caso del OP, agrupar código con la plantilla de datos ... Prefiero probar un enfoque diferente ... usar el modelo de Comando, por ejemplo. Necesito más detalles sobre el problema del OP para recomendar una solución de diferencias.
Gishu
1
Totalmente en desacuerdo. Con MVVM, hay un escenario en el que tener código detrás es extremadamente útil: desarrollar propiedades adjuntas. Póngalo a funcionar con el código detrás, luego transfiéralo a una propiedad adjunta. Esto es mucho más rápido que simplemente desarrollar la propiedad adjunta desde cero, a menos que tenga un cerebro del tamaño de Manhattan.
Contango