2016-05-10 20 views
0

私は、MahAppsのAccentedSquareButtonStyleに基づいて、ハイライト効果付きの画像ボタンカスタムコントロールを作成しています。 ImageButton.xamlカスタムコントロール "ImageButton"に画像が表示されないのはなぜですか?

<UserControl x:Class="NQR_GUI_WPF.ImageButton" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:local="clr-namespace:NQR_GUI_WPF" 
     mc:Ignorable="d" > 
<Button Style="{StaticResource AccentedSquareButtonStyle}" Background="Transparent" Foreground="Transparent" BorderThickness="0" Width="24" Height="24" TouchDown="Button_TouchDown"> 
    <Grid Background="Transparent"> 
     <ContentControl> 
      <ContentControl.Style> 
       <Style TargetType="{x:Type ContentControl}"> 
        <Setter Property="Content" Value="{Binding Image, RelativeSource={RelativeSource TemplatedParent}}"/> 
        <Style.Triggers> 
         <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=IsMouseOver}" Value="True" > 
          <Setter Property="Content" Value="{Binding HighlightedImage, RelativeSource={RelativeSource TemplatedParent}}"/> 
         </DataTrigger> 
         <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=IsPressed}" Value="True" > 
          <Setter Property="Content" Value="{Binding ClickedImage, RelativeSource={RelativeSource TemplatedParent}}"/> 
         </DataTrigger> 
        </Style.Triggers> 
       </Style> 
      </ContentControl.Style> 
     </ContentControl> 
    </Grid> 
</Button> 

ImageButton.xaml.cs

namespace NQR_GUI_WPF 
{ 
/// <summary> 
/// Interaction logic for ImageButton.xaml 
/// </summary> 
public partial class ImageButton : UserControl 
{ 
    public static DependencyProperty ImageProperty = DependencyProperty.Register("Image", typeof(Canvas), typeof(ImageButton)); 
    public static DependencyProperty ClickedImageProperty = DependencyProperty.Register("ClickedImage", typeof(Canvas), typeof(ImageButton)); 
    public static DependencyProperty HighlightedImageProperty = DependencyProperty.Register("HighlightedImage", typeof(Canvas), typeof(ImageButton)); 

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

    public Canvas Image 
    { 
     get { return (Canvas)base.GetValue(ImageProperty); } 
     set { base.SetValue(ImageProperty, value); } 
    } 

    public Canvas ClickedImage 
    { 
     get { return (Canvas)base.GetValue(ClickedImageProperty); } 
     set { base.SetValue(ClickedImageProperty, value); } 
    } 

    public Canvas HighlightedImage 
    { 
     get { return (Canvas)base.GetValue(HighlightedImageProperty); } 
     set { base.SetValue(HighlightedImageProperty, value); } 
    } 

    private void Button_TouchDown(object sender, TouchEventArgs e) 
    { 
     Keyboard.ClearFocus(); 
    } 
} 

}

例アイコン:

<Canvas x:Key="printIcon" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_printer_text" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0"> 
      <Path Width="44" Height="45" Canvas.Left="16" Canvas.Top="17" Stretch="Fill" Fill="{Binding Source={x:Static prop:Settings.Default}, Path=theme, Converter={StaticResource idealForegroundConverter}}" Data="F1 M 25,27L 25,17L 51,17L 51,27L 47,27L 47,21L 29,21L 29,27L 25,27 Z M 16,28L 60,28L 60,51L 52,51L 52,46L 55,46L 55,33L 21,33L 21,46L 24,46L 24,51L 16,51L 16,28 Z M 25,39L 28,39L 28,52L 35,52L 35,59L 48,59L 48,39L 51,39L 51,62L 33,62L 25,54L 25,39 Z M 46,55L 38,55L 38,52L 46,52L 46,55 Z M 46,49L 30,49L 30,46L 46,46L 46,49 Z M 46,43L 30,43L 30,40L 46,40L 46,43 Z "/> 
     </Canvas> 

問題は、MainWindowでは、App.xamlに格納されている画像を追加した後で、コントロールが空である(画像が表示されていない)ということです。

<local:ImageButton Image="{StaticResource printIcon}" HighlightedImage="{StaticResource printIconHighlighted}" ClickedImage="{StaticResource printIconClicked}" Grid.Column="1" HorizontalAlignment="Left" Height="46" Margin="36,10,0,0" VerticalAlignment="Top" Width="100"/> 

(コントロールデザイナービューで画像が示されているが)、私は成功せず、コントロールテンプレートに直接画像を結合しようとしています。 コントロール画像が表示されないのはなぜですか?

+0

あなたは、x:typeが指定された構文 –

+0

を使って、{RelativeSource = {RelativeSource Mode = FindAncestor、 AncestorType = {x:Type local:ImageButton}}、Path = Image}を試してみましたか?あなたのDependencyPropertiesを 'Image'プロパティに' Canvas'を使っているようなUserControlsにするのは良い考えではありません。 UserControlsは、UIの1つの親にのみ割り当てることができるので、他のコントロールが 'Canvas'' printIcon'を追加しようとすると、例外がスローされます。画像を使用するか、テンプレートを代わりに使用することをお勧めします。 'Template'はクッキーカッターのようなものです。レンダリングが必要な時はいつでも、テンプレートコントロールが何であれ作成します。この方法では、同じCanvasインスタンスにアクセスしようとする2つのコントロールの問題に遭遇することはありません。 – Rachel

答えて

1

UserControlはこのための最適な方法ではありません。 UserControlsは、汎用WPFコントロールを記述するためのものではありません。あなたはそれをすることができますが、最も簡単な方法ではありません。最も簡単な方法は、通常のコントロール(たいていはContentControlまたはHeaderedContentControl)をサブクラス化し、それにスタイルとテンプレートを書き込むことです。このテクニックを一度釘付けにすると、必要に応じて弾くことができます。しばしば、既存のコントロール用の特殊なテンプレートを書くことができますが、独自のサブクラスButtonが必要な場合があります。

私はかなりあなたがそれらを定義したように、追加の依存関係プロパティで、ButtonのサブクラスとしてImageButtonを書くだろうが、私はそう消費者がXAMLをレンダリングすることができることで何かを詰め込むことができますタイプObjectのそれらを作ると思います。彼らに使用できるロープをすべて与えない理由はありません。そしてImageプロパティの代わりにContentプロパティを使用します。これは物事を簡素化するためです。

画像以外のコンテンツを防止する必要がある場合は、Objectよりも特殊なコンテンツタイプを使用できますが、その制限を導入する特別な理由は言及していません。

C#:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Input; 

namespace NQR_GUI_WPF 
{ 
    /// <summary> 
    /// Interaction logic for ImageButton.xaml 
    /// </summary> 
    public class ImageButton : Button 
    { 
     public ImageButton() 
     { 
      TouchDown += ImageButton_TouchDown; 
     } 

     private void ImageButton_TouchDown(object sender, TouchEventArgs e) 
     { 
      Keyboard.ClearFocus(); 
     } 

     #region Dependency Properties 
     public static DependencyProperty ClickedContentProperty = DependencyProperty.Register("ClickedContent", typeof(Object), typeof(ImageButton)); 
     public static DependencyProperty HighlightedContentProperty = DependencyProperty.Register("HighlightedContent", typeof(Object), typeof(ImageButton)); 

     public Object ClickedContent 
     { 
      get { return (Object)base.GetValue(ClickedContentProperty); } 
      set { base.SetValue(ClickedContentProperty, value); } 
     } 

     public Object HighlightedContent 
     { 
      get { return (Object)base.GetValue(HighlightedContentProperty); } 
      set { base.SetValue(HighlightedContentProperty, value); } 
     } 
     #endregion Dependency Properties 
    } 
} 

XAMLのresoure辞書ImageButton.xaml:

<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:nqrgui="clr-namespace:NQR_GUI_WPF" 
    > 

    <Style TargetType="{x:Type nqrgui:ImageButton}"> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="{x:Type nqrgui:ImageButton}"> 
        <Grid> 
         <ContentControl 
          Content="{TemplateBinding Content}" 
          x:Name="PART_Content" 
          /> 
        </Grid> 
        <ControlTemplate.Triggers> 
         <Trigger Property="IsMouseOver" Value="True"> 
          <Setter 
           TargetName="PART_Content" 
           Property="Content" 
           Value="{Binding HighlightedContent, RelativeSource={RelativeSource TemplatedParent}}" 
           /> 
         </Trigger> 
         <Trigger Property="IsPressed" Value="True"> 
          <Setter 
           TargetName="PART_Content" 
           Property="Content" 
           Value="{Binding ClickedContent, RelativeSource={RelativeSource TemplatedParent}}" 
           /> 
         </Trigger> 
        </ControlTemplate.Triggers> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
</ResourceDictionary> 

そして、ここでは、あなたがそれを使用したい方法は次のとおりです。

<Window 
    ... 
    xmlns:nqrgui="clr-namespace:NQR_GUI_WPF" 
    ... 
    > 

<!-- Or better yet, merge ImageButton.xaml in App.xaml so everybody can see it --> 
    <Window.Resources> 
     <ResourceDictionary> 
      <ResourceDictionary.MergedDictionaries> 
       <ResourceDictionary Source="ImageButton.xaml" /> 
      </ResourceDictionary.MergedDictionaries> 
     </ResourceDictionary> 
    </Window.Resources> 

... 

    <!-- As noted, Content, HighlightedContent, and ClickedContent 
    can be images -- or also paths, text, ANYTHING XAML can render. 
    --> 
    <nqrgui:ImageButton 
     Content="Content" 
     HighlightedContent="Highlighted" 
     ClickedContent="Clicked" 
     /> 

そして、あなたは本当に絶対に凶暴に行くことができます内容:

<!-- Don't try this in a UI anybody will have to use! --> 
    <nqrgui:ImageButton 
     Content="Content" 
     ClickedContent="Clicked" 
     > 
     <nqrgui:ImageButton.HighlightedContent> 
      <StackPanel Orientation="Horizontal"> 
       <Border 
        BorderBrush="Gray" 
        Background="GhostWhite" 
        BorderThickness="1"> 
        <Path 
         Width="20" 
         Height="20" 
         Stroke="Black" 
         StrokeThickness="2" 
         Data="M 0,0 L 20,20 M 0,20 L 20,0" 
         Margin="2" 
         /> 
       </Border> 
       <nqrgui:ImageButton 
        Content="LOL" 
        ClickedContent="Don't Click Me, Bro!" 
        HighlightedContent="I heard you like buttons" 
        /> 
      </StackPanel> 
     </nqrgui:ImageButton.HighlightedContent> 
    </nqrgui:ImageButton> 
+0

まず、詳細な回答をいただき、ありがとうございます。しかし、私はあなたのコードで次の問題が発生しました: 1. VSは自動的に次のものを生成するので、C#: "タイプ 'ImageButton'の宣言で部分修飾子が見つからず、 'ImageButton'の部分宣言で異なる基本クラスを指定してはいけません。 XAMLリソースディクショナリ:メンバ "IsPressed"が認識されないか、アクセス不能です。 。 私はそれを有効にしようとしています。 –

+0

@CristianM 'obj/Debug/ImageButton.g.i.cs'を削除しても、VSはまだそれを再作成しますか?その場合は、古いImageButtonファイル(rootとbranch)をすべて削除して、「新規クラス」と「新しいリソースディクショナリ」を使用して再度作成してみてください。たぶん、ちょっと違う名前で、確かに。 'IsPressed'問題は、残っている.g.i.csファイルが、' IsPressed'を持たない 'CustomControl'のサブクラスとしてImageButtonを宣言している可能性があります。ボタンのサブクラスだと完全に把握すれば、 'IsPressed'は問題にならないはずです。 –

+0

あなたは最高です!出来た!もう少し質問してください。マウスを上書きするとコンテンツが表示されないので、「IsMouseOver」と「IsPressed」がトリガされるようにスタイルを変更する必要があります。この場合、マウスを動かすとイベントが発生するため、アイコンの線をクリックします。 –

0

あなたはTemplateParentを使用していなく、誤ってこの

{Binding Image, RelativeSource={RelativeSource TemplatedParent}} 

それは、私は以下のようにそれを行っている。この

{Binding RelativeSource={RelativeSource Mode=FindAncestor, 
AncestorType=ImageButton}, Path=Image} 
+0

「ImageButtonはWindows Presentation Foundation(WPF)プロジェクトではサポートされていません。それはAncestorType = Buttonで構築されますが、問題は残ります。 –

+0

ImageButtonは一般的な名前であり、参照している他のパッケージに存在する可能性があります。AncestorTypeで完全修飾名(名前空間を含む)を使用して、ImageButtonのバージョンを使用していることを確認してください。 –

+0

AncestorType = NQR_GUI_WPF.ImageButtonを使用しましたが、成功しませんでした。 –

0

のようなものでなければなりません

<Controls:MetroWindow.Resources> 
    <ImageBrush Stretch="Fill" x:Key="CloseImage" ImageSource="../images/Close.png" /> 
    <ImageBrush x:Key="CloseImageRed" ImageSource="../images/CloseRed.jpg" /> 
    </Controls:MetroWindow.Resources> 

<Button> 
     <Button.Style> 
     <Style TargetType="Button"> 
      <Setter Property="Background" Value="{StaticResource CloseImageRed}"/> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="{x:Type Button}"> 
         <Border Background="{TemplateBinding Background}" 
           BorderBrush="{TemplateBinding BorderBrush}" 
           BorderThickness="{TemplateBinding BorderThickness}"> 
       <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
           Margin="{TemplateBinding Padding}" 
           VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
           SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
           RecognizesAccessKey="True"/> 
         </Border> 
        <ControlTemplate.Triggers> 
         <Trigger Property="IsMouseOver" Value="True"> 
          <Setter Property="Background" Value="{StaticResource CloseImage}"/> 
         </Trigger> 
        </ControlTemplate.Triggers> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter>              
    </Style> 
</Button.Style> 
</Button> 

見てください。

+0

ありがとうございます!あなたのコードは、キャンバスではなく実際の画像を使用する画像ボタンに便利です。しかし、私はキャンバスを使用します。 –

0

カスタマイズしたボタンにUserControl.Contentを設定しています。設定したいものはUserControl.ContentTemplateと思います。

.Contentからは、バインドする "TemplatedParent"がありません。しかし、これがTemplateの場合、TemplatedParentは、テンプレートが定義されているUserControlを指します。この場合、ImageButton UserControlを参照すると、正しくImageプロパティにアクセスできます。

<UserControl ..> 
    <UserControl.ContentTemplate> 
     <ControlTemplate> 
      <!-- TemplatedParent bindings should refer to UserControl from here --> 
      <Button ... /> 
     </ControlTemplate> 
    </UserControl.ContentTemplate> 
</UserControl> 

これはまた、あなたが完全に例えば「いくつかのテキスト」

を含むテキスト要素を使用してボタンのXAMLコードを置き換えることなく

<local:ImageButton Content="Some Text" /> 

のようなものを書くことができます、あなたは右の持っているもの今すぐにレンダリングする

<UserControl> 
    <Button /> <!-- Button is .Content, and can be replaced by XAML using the control --> 
</UserControl> 

これはContentTemplateの場合はldは次のようにレンダリングします

<UserControl> 
    <Button> <!-- Button is ContentTemplate, so wraps any content given by external XAML --> 
     <Content /> 
    </Button> 
</UserControl> 
関連する問題