7

とを使用して、WPFカスタムコントロールを作成してButtonImageますTextImagePathコントロールに2つの依存関係プロパティを追加しましTextた。コントロールテンプレート(Themes \ Generic.xaml内)は、画像とテキストを水平方向に配置する単純なスタックパネルです。

Textプロパティは正常に動作します。しかし、何らかの理由で、依存関係プロパティを使用TemplateBindingしてパスを取得すると、テストプロジェクトのサンプル画像が表示されません。カスタムコントロールのを一時的に画像へのパスにImagePath置き換えて画像をテストしました。その場合、画像が表示されます。TemplateBinding

この分野の経験が豊富な人が、コントロールが期待どおりに機能しない理由を調べて教えてくれることを願っています。ご協力いただきありがとうございます。

私のVS2008ソリューションには、CustomControlDemoという1つのプロジェクトが含まれています。プロジェクトには、カスタムコントロールTaskButton.csと、コントロールのテストに使用するメインウィンドウWindow1.xamlが含まれています。私のテスト画像calendar.pngは、プロジェクトのルートレベルのResourcesフォルダーにあり、Generic.xamlは、同じくプロジェクトのルートレベルのThemesフォルダーにあります。

これが私のカスタムコントロールのコードです(TaskButton.csから):

using System.Windows;
using System.Windows.Controls;

namespace CustomControlDemo
{
    public class TaskButton : RadioButton
    {
        #region Fields

        // Dependency property backing variables
        public static readonly DependencyProperty ImagePathProperty;
        public static readonly DependencyProperty TextProperty;

        #endregion

        #region Constructors

        /// <summary>
        /// Default constructor.
        /// </summary>
        static TaskButton()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TaskButton), new FrameworkPropertyMetadata(typeof(TaskButton)));

            // Initialize ImagePath dependency properties
            ImagePathProperty = DependencyProperty.Register("ImagePath", typeof(string), typeof(TaskButton), new UIPropertyMetadata(null));
            TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(TaskButton), new UIPropertyMetadata(null));
        }

        #endregion

        #region Dependency Property Wrappers

        /// <summary>
        /// The ImagePath dependency property.
        /// </summary>
        public string ImagePath
        {
            get { return (string)GetValue(ImagePathProperty); }
            set { SetValue(ImagePathProperty, value); }
        }

        /// <summary>
        /// The Text dependency property.
        /// </summary>
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        #endregion
    }
}

そして、これが(Generic.xamlからの)コントロールテンプレートです:

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


    <Style TargetType="{x:Type local:TaskButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:TaskButton}">
                    <StackPanel Height="Auto" Orientation="Horizontal">
                        <Image Source="{TemplateBinding ImagePath}"  Width="24" Height="24" Stretch="Fill"/>
                        <TextBlock Text="{TemplateBinding Text}"  HorizontalAlignment="Left" Foreground="{DynamicResource TaskButtonTextBrush}" FontWeight="Bold"  Margin="5,0,0,0" VerticalAlignment="Center" FontSize="12" />
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

最後に、コントロールのテストに使用しているWindow1マークアップを次に示します。

<Window x:Class="CustomControlDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:customControl="clr-namespace:CustomControlDemo"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <customControl:TaskButton ImagePath="Resources\calendar.png" Text="Calendar" />
    </Grid>
</Window>

画像パスが機能しない理由はありますか?再度、感謝します。

4

4 に答える 4

10

技術的に正しいので、cwapの回答を受け入れられた回答として残します。ただし、この問題を解決する簡単な方法があることがわかりました。

TemplateBindings は、第一級の Binding オブジェクトではありません。これらは軽量になるように設計されているため、一方向であり、他の Binding オブジェクトのいくつかの機能が欠けています。最も顕著なのは、ターゲットに関連付けられた既知の型コンバーターをサポートしていないことです。MacDonald のPro WPF in C# 2008を参照してください。872. これが cwap が正しく応答する理由で、おそらく型コンバーターを作成し、それをカスタム ボタンのコントロール テンプレートで特に参照する必要があります。

ただし、TemplateBinding を使用してコントロール テンプレートをカスタム コントロールの ImagePath プロパティにバインドする必要はありません。単純な古い Binding オブジェクトを使用できます。カスタム コントロールのテンプレートの改訂されたマークアップは次のとおりです。

<!-- Task Button Default Control Template-->
<Style TargetType="{x:Type local:TaskButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:TaskButton}">
                <StackPanel Height="Auto" Orientation="Horizontal">
                    <Image Source="{Binding Path=ImagePath, RelativeSource={RelativeSource TemplatedParent}}" Width="24" Height="24" Stretch="Fill" Margin="10,0,0,0" />
                    <TextBlock Text="{TemplateBinding Text}"  HorizontalAlignment="Left" Foreground="{TemplateBinding Foreground}" FontWeight="Bold"  Margin="5,0,10,0" VerticalAlignment="Center" FontSize="12" />
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

テンプレートの ImageControl を見ると、変更が確認できます。同じオブジェクトの RelativeSource プロパティに注意してください。このプロパティを ={RelativeSource TemplatedParent} に設定すると、TaskButton の Window1 インスタンスに相対パスを入力し、カスタム コントロールで正しく解決できるようになります。

したがって、このスレッドを調査している他の人への私の推奨事項は、値コンバーターをスキップして、Image プロパティの TemplateBinding から Binding に切り替えることです。

また、MSDN WPF フォーラムで同様の質問に対してこの回答を提供してくれた Marco Zhou にも感謝します。

于 2009-12-20T20:16:52.620 に答える
4

画像はソースとして文字列を取りません:)これはインテリセンスで見ることができます。ImageSourceにバインドする必要があります(またはIValueConverterを使用して文字列をImageSourceに変換します)

この変換を行う方法のヒントについては、この質問を参照してください。

于 2009-12-20T14:16:01.683 に答える
2

実際、これらの答えはどちらも正しくありません。

{TemplateBinding ImagePath}はショートカットにすぎず、{Binding Path=ImagePath, RelativeSource={RelativeSource TemplatedParent}}ほぼ完全に同じです。

また、文字列を指定すると、アプリケーションのパフォーマンスに影響を与えますImagePathが、正しく解決されます。実際の問題は、テスト用にxamlでImageSource提供されている相対および絶対イメージパスに関係しています。ImagePath="Resources\calendar.png"これにより、コンパイラは、パスの定義で/の代わりに\を使用するため、指定されたパスが絶対であると考えるようになります。

長い形式のバインディングが機能し、ショートカットが機能しない理由は、提供された画像のソース(Resources \ calendar.png)が絶対パスではなく相対パスであり、したがって画像であるという手がかりをコンパイラに提供するためです。が見つかり、バインディングが機能します。バインディングをデバッグすると、ショートカットが提供された文字列を画像ソースに解決しようとしますが、ファイル「Resources \calendar.png」が見つかりません。画像に完全なURIを指定した場合、つまり、"C:\...\Resources\calendar.png"対応するブレンド表記"/application;component/Resources/calendar.png"画像が見つかり、バインディングが解決されます。

この点は、リソースとしてコンパイルされた画像ではなく、外部ソースからの画像を最終的なコンパイルに参照しようとする場合に非常に重要になります。

于 2011-12-05T23:12:24.613 に答える
0

簡単な方法(テスト済み)1-このようにvalueConverterを作成します

  public class objectToImageSourceConverter:IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {

            string packUri =value.ToString();
            ImageSource Source = new ImageSourceConverter().ConvertFromString(packUri) as ImageSource;
            return Source;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

次の xaml のように、イメージ ソースを親の文字列プロパティ (「タグ」プロパティを使用) に 2 バインドします。

<Image HorizontalAlignment="Right"  Height="Auto" Margin="0,11.75,5.5,10.75" VerticalAlignment="Stretch" Width="40.997" Source="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}"/>
于 2015-08-18T18:16:49.517 に答える