2011-04-08 15 views
9

He comenzado a mover varias Image comunes en un ResourceDictionary y noté un comportamiento extraño en mi aplicación WPF. Si el Image se usa en un MenuItem y en un Button en un ToolBar, cuando abro el Menu, la imagen desaparece del Button.Las imágenes en XAML ResourceDictionary desaparecen en la barra de herramientas cuando se abre el menú

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Image x:Key="NewImage" 
      Source="/SomeApplication;component/Resources/NewDocumentHS.png" 
      Stretch="None"/> 
    <!-- ... --> 

XAML pertinente de la Window:

<Menu> 
    <MenuItem Header="_File"> 
     <MenuItem Header="_New" 
        Command="{Binding NewCommand}" 
        Icon="{DynamicResource NewImage}" /> 
<!-- ... --> 
<ToolBarTray> 
    <ToolBar> 
     <Button Command="{Binding NewCommand}" 
       Content="{DynamicResource NewImage}" /> 

supongo que esto es una advertencia de los recursos en un ResourceDictionary, pero soy incapaz de descubrir la solución adecuada para esto. El comportamiento se produce con StaticResource y DynamicResource. Tampoco parece verse afectado si el ResourceDictionary se sostiene solo o si se fusiona con otros. Ningún otro recurso comparte esa clave tampoco.

Editar: Además, agregar PresentationOptions:Freeze="True" a las imágenes no cambió la situación.

+2

¡Esto suena inquietantemente similar a mi experiencia con los estilos Path en Silverlight 4! El tiempo de ejecución solo representa la primera instancia del recurso aplicado, después de eso simplemente vacío donde la forma (en mi caso, los iconos de vector) debería ser :(No he encontrado ninguna solución alternativa ... – dain

Respuesta

7

La clase de imagen es visual, por lo que solo puede aparecer en el árbol visual en una ubicación. Por lo tanto, no puede compartirlo entre múltiples MenuItems/Buttons/etc.

Sin embargo, puede compartir el valor de ImageSource (es decir, Image.Source).

En WPF, creo que puede usar x:Shared = "False" para forzar a WPF a crear una nueva instancia para cada solicitud.

+0

Ahora que mencionas que es un 'Visual '¡El comportamiento parece completamente obvio! El bit' x: Shared' no era del todo obvio. Trabajando bien, muchas gracias. – user7116

2

No puede usar un control de imagen en varios lugares, solo puede aparecer en el árbol visual en un solo lugar, por lo que si se realiza la llamada al recurso, la imagen se está arrebatando al propietario anterior.

Editar:x:Shared="False" obviamente una solución mejor que todos mis sugerencias a continuación, me pregunto por qué una propiedad tan importante no se presenta en el Intellisense -_-


Este comportamiento es un poco de un dolor, normalmente uso para predefinir un IconStyle y el BitmapImages para el Origen de las imágenes, pero creo nuevas Imágenes para cada MenuItem donde pueda necesitarlo.

También puede crear un DataTemplate para su icono:

Recursos:

<Style x:Key="IconImageStyle" TargetType="{x:Type Image}"> 
     <Setter Property="MaxWidth" Value="16"/> 
     <Setter Property="MaxHeight" Value="16"/> 
    </Style> 
    <DataTemplate x:Key="Icon_Close_Template"> 
     <Image Style="{StaticResource IconImageStyle}" 
       Source="pack://application:,,,/Images/Close.ico"/> 
    </DataTemplate> 

Uso:

<Menu> 
    <MenuItem Header="File"> 
     <MenuItem Header="Close"> 
      <MenuItem.Icon> 
       <ContentPresenter ContentTemplate="{StaticResource Icon_Close_Template}"/> 
      </MenuItem.Icon> 
     </MenuItem> 
     <MenuItem Header="Close"> 
      <MenuItem.Icon> 
       <ContentPresenter ContentTemplate="{StaticResource Icon_Close_Template}"/> 
      </MenuItem.Icon> 
     </MenuItem> 
    </MenuItem> 
</Menu> 

Dado que las plantillas se crean a través de fábricas esto va a funcionar, todavía se infla de manera significativa la XAML aunque ...

Para evitar esto, podría para e Xample escribir una extensión de marcado, éste es muy simple y sólo copia los valores de los Source y Style propiedades, también se podría utilizar la reflexión o cualquier otro medio para crear una copia completa:

[MarkupExtensionReturnType(typeof(object))] 
public class IconExtension : MarkupExtension 
{ 
    private Image icon; 
    public Image Icon 
    { 
     get { return icon; } 
     set { icon = value; } 
    } 

    public IconExtension() { } 
    public IconExtension(Image icon) 
    { 
     Icon = icon; 
    } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     if (Icon == null) throw new ArgumentNullException("Icon"); 
     return new Image() { Source = Icon.Source, Style = Icon.Style }; 
    } 
} 

Puede ser utilizado como esto:

<Style x:Key="IconImageStyle" TargetType="{x:Type Image}"> 
    <Setter Property="MaxWidth" Value="16"/> 
    <Setter Property="MaxHeight" Value="16"/> 
</Style> 
<Image x:Key="Icon_Close" Style="{StaticResource IconImageStyle}" Source="pack://application:,,,/Images/Close.ico"/> 
<!-- ... --> 
<MenuItem Header="File"> 
    <MenuItem Header="Close" Icon="{m:Icon {StaticResource Icon_Close}}"/> 
    <MenuItem Header="Close" Icon="{m:Icon {StaticResource Icon_Close}}"/> 
</MenuItem> 
Cuestiones relacionadas