7

画像を含むシンプルなボタンを実装しました。

    <Button Command="{Binding ButtonCommand, ElementName=ImageButtonControl}">
        <StackPanel Orientation="Horizontal">
            <Image Source="{Binding ButtonImage, ElementName=ImageButtonControl}"/>
            <TextBlock Text="{Binding ButtonText, ElementName=ImageButtonControl}" Margin="2,0,0,0"/>
        </StackPanel>
    </Button>

ご覧のとおり、このUserControlにICommandをアタッチできるようにするために、ButtonCommandプロパティを公開しています。

public partial class ImageButton : UserControl
{
    /// <summary>
    /// The dependency property that gets or sets the source of the image to render.
    /// </summary>
    public static DependencyProperty ImageSourceProperty = 
        DependencyProperty.Register("ButtonImage", typeof(ImageSource), typeof(ImageButton));

    public static DependencyProperty TextProperty =
        DependencyProperty.Register("ButtonText", typeof(string), typeof(ImageButton));

    public static DependencyProperty ButtonCommandProperty =
        DependencyProperty.Register("ButtonCommand", typeof(ICommand), typeof(ImageButton));

    public ImageButton()
    {
        this.DataContext = this;
        InitializeComponent();
    }

    /// <summary>
    /// Gets or sets the button command.
    /// </summary>
    public ICommand ButtonCommand
    {
        get { return (ICommand)GetValue(ImageButton.ButtonCommandProperty); }
        set { SetValue(ImageButton.ButtonCommandProperty, value); }
    }

    /// <summary>
    /// Gets or sets the button image.
    /// </summary>
    public ImageSource ButtonImage
    {
        get { return (ImageSource)GetValue(ImageButton.ImageSourceProperty); }
        set { SetValue(ImageButton.ImageSourceProperty, value); }
    }

    /// <summary>
    /// Gets or sets the button text.
    /// </summary>
    public string ButtonText
    {
        get { return (string)GetValue(ImageButton.TextProperty); }
        set { SetValue(ImageButton.TextProperty, value); }
    }
}

次に、ボタンを宣言すると、次のようになります。

<uc:ImageButton Grid.Row="1" Grid.Column="0" ButtonCommand="{Binding AttachContextCommand}" ButtonImage="{StaticResource AssociateImage}" ButtonText="Associer"/>

そしてbadaboom、ImageButtonをクリックしても何も起こりません。ImageButtonを単純なボタンに置​​き換えると、ICommandが呼び出されます。

Buttonクラスを拡張してICommandをバインドしようとしましたが、もう一度、機能しませんでした...

感謝します!

どうも。

4

4 に答える 4

7

これは、スタイルといくつかの添付プロパティを使用して、よりクリーンな方法で実現できます。

添付されたプロパティには、特定の情報が保存されます。スタイルはこれらのプロパティを使用して、必要な外観を構築します。

要素は引き続きボタンであるため、コマンドと他のすべてが機能します。

 public class ImageButton
    {

        public static ImageSource GetImage(DependencyObject obj)
        {
            return (ImageSource)obj.GetValue(ImageProperty);
        }

        public static void SetImage(DependencyObject obj, ImageSource value)
        {
            obj.SetValue(ImageProperty, value);
        }

        public static readonly DependencyProperty ImageProperty =
            DependencyProperty.RegisterAttached("Image", typeof(ImageSource), typeof(ImageButton), new UIPropertyMetadata(null));

        public static String GetCaption(DependencyObject obj)
        {
            return (String)obj.GetValue(CaptionProperty);
        }

        public static void SetCaption(DependencyObject obj, String value)
        {
            obj.SetValue(CaptionProperty, value);
        }

        public static readonly DependencyProperty CaptionProperty =
            DependencyProperty.RegisterAttached("Caption", typeof(String), typeof(ImageButton), new UIPropertyMetadata(null));

    }

<Style TargetType="{x:Type Button}"
               x:Key="ImageButton">
            <Setter Property="ContentTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Image Source="{Binding Path=(local:ImageButton.Image), RelativeSource={RelativeSource AncestorType={x:Type Button}}}" />
                            <TextBlock Text="{Binding Path=(local:ImageButton.Caption), RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
                                       Margin="2,0,0,0" />
                        </StackPanel>
                    </DataTemplate>
                </Setter.Value>
            </Setter>   
        </Style>

次に、これを使用してボタンを宣言できます。

   <Button Style="{DynamicResource ImageButton}"
                        local:ImageButton.Caption="Foo" 
                        local:ImageButton.Image="..." />

ノート:

「テンプレート」プロパティを調べて ControlTemplate と TemplateBindings を使用する方がきれいだと確信していますが、それはコンテンツの境界線やその他のものを再作成することを意味するため、デフォルトを定義するだけの場合「コンテンツ」、私の例は行くべき道だと思います。

于 2009-03-16T14:17:54.160 に答える
4

ボタンに必要な唯一の追加機能が画像を表示することである場合、間違った方向からアプローチしていると思います。UI コントロールがルックレスであるため、WPF は素晴らしいものです。 つまり、Control は単なる機能の定義 + 外観を定義するためのテンプレートです。これは、テンプレートをいつでも交換して外観を変更できることを意味します。また、ほぼすべてのコンテンツをほぼすべてのコントロール内に配置できます

たとえば、xaml で必要なすべての外観を持つボタンを定義するには、次のようにします。

<Window ...>
    ...
    <Button Command="{Binding AttachContextCommand}">
        <StackPanel Orientation="Horizontal">
            <Image Source="{StaticResource AssociateImage}"/>
            <TextBlock Text="Associer"/>
        </StackPanel>
    </Button>
    ...
</Window>

WPF を使用すると、何かのルック アンド フィールを変更するたびに、新しい CustomControl または UserControl を定義する必要がないことに注意してください。CustomControl が必要になるのは、既存のコントロールに機能を追加する場合、または他のコントロールに存在しない機能を作成する場合だけです。

コメントによる編集:

ボタンのコンテンツを毎回定義するのを避けたい場合、他のオプションは、関心のあるすべてを定義する poco (プレーンな古い CLR オブジェクト) クラスを使用することです (私の例は、私には理にかなっているので、ツールバーに対してこれを行っています):

public class ToolBarItem : INotifyPropertyChanged
{
    public string Text { get ... set ... }
    public ICommand Command { get ... set ... }
    public ImageSource Image { get ... set ... }
}

どこかにデータ テンプレートが定義されています (App.xaml、Window.Resources など)。

<DataTemplate DataType="{x:Type l:ToolBarItem}">
    <Button Command="{Binding Command}">
        <StackPanel Orientation="Horizontal">
            <Image Source="{Binding Image}"/>
            <TextBlock Text="{Binding Text}"/>
        </StackPanel>
    </Button>
</DataTemplate>

そして、次のように xaml でその男を使用します。

<Window ...>
    ...
    <ContentControl>
        <ContentControl.Content>
            <l:ToolBarItem Image="..." Command="..." Text="..."/>
        </ContentControl.Content>
    </ContentControl>
    ...
</Window>

あなたがやろうとしている方法が、あなたができる最もWPFの方法であるかどうかはわかりません。

編集 2 番目のコメントに基づいて更新されました 。申し訳ありませんが、それを囲む ContentControl を含めるのを忘れていました。それを思い出したので、コンテンツを手動で指定している元の場合よりもそれほど冗長ではないことに気付きました。元の質問に役立つ新しい回答を投稿します。

于 2009-03-14T04:38:09.757 に答える
1

元の質問に再回答するには:

あなたがやりたいと思うことは、 ImageButton という新しい CustomControl を作成することです。次に、Control ではなく Button から拡張するように変更します。Button には既に Command プロパティがあるため、Command プロパティは必要ありません。Image プロパティを追加するだけで済み、Text プロパティの代わりに Content プロパティをボタンから再利用できます。

CustomControl が作成されると、ImageButton の既定のスタイルのエントリが Generic.xaml に追加されます。Template プロパティの Setter で、ControlTemplate を次のように変更できます。

<ControlTemplate TargetType="{x:Type local:ImageButton}">
    <StackPanel Orientation="Horizontal">
        <Image Source="{TemplateBinding Image}"/>
        <ContentPresenter/>
    </StackPanel>
</ControlTemplate>

次に、もう一度、それを使用したい場合:

<Window ... >
...
    <l:ImageButton Image="{StaticResource ...}" Command="...">
        Associer
    </l:ImageButton>
...
</Window>
于 2009-03-16T17:42:58.737 に答える
0

組み込みの WPF ボタンには、クリックに応答して添付コマンドを起動するコードが含まれています。「ImageButton」は UserControl から派生しているため、その動作は得られません。おそらく、必要なものを取得するための最短ルートは、ImageButton クラスが実際に WPF Button クラスから派生することです。これを実現するには、ImageButton のマークアップを次のように変更します。

<UserControl
...
>
...
</UserControl>

<Button
...
>
...
</Button>

次に、ImageButton の基本クラスを からUserControlに変更しButtonます。

すべてが機能する前に、おそらく他の小さな変更を加える必要があります。

于 2009-03-13T18:23:48.030 に答える