2009-12-20 7 views
7

ImageText이있는 Button을 만듭니다. 컨트롤에 두 개의 종속성 속성 인 ImagePathText을 추가했으며 컨트롤 템플릿 (Themes \ Generic.xaml)은 이미지와 텍스트를 가로로 정렬하는 간단한 스택 패널입니다.WPF 사용자 지정 컨트롤 : 이미지에 템플릿 바인딩

Text 속성이 정상적으로 작동합니다. 그러나 어떤 이유로 인해 을 ImagePath 종속성 속성에 사용하여 경로를 가져 오면 내 테스트 프로젝트의 샘플 이미지가 나타나지 않습니다. 사용자 지정 컨트롤의 TemplateBinding을 일시적으로 이미지의 경로로 바꾸어 이미지를 테스트 한 결과이 이미지가 나타납니다.

나는이 분야에서 더 많은 경험을 가진 사람이 왜 컨트롤이 예상대로 작동하지 않는지 살펴보고 왜 좋을까요? 당신의 도움을 주셔서 감사합니다.

내 VS 2008 솔루션에는 CustomControlDemo 프로젝트가 하나 있습니다. 이 프로젝트에는 컨트롤을 테스트하는 데 사용하는 사용자 지정 컨트롤 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

이미지는 문자열을 소스로 사용하지 않습니다. intellisense에서이를 볼 수 있습니다. ImageSource에 바인딩해야합니다. (문자열을 ImageSource로 변환하려면 IValueConverter를 사용해야합니다.)

이 변환을 수행하는 방법에 대한 팁은 this을 참조하십시오.

9

나는 기술적으로 정확하기 때문에 받아 들인 대답으로 cwap의 대답을 남겨 두겠습니다. 그러나이 문제를 해결하는 더 쉬운 방법이 있음이 밝혀졌습니다.

TemplateBinding은 1 급 Binding 객체가 아닙니다. 가볍도록 디자인 되었기 때문에 단방향이고 다른 Binding 객체의 일부 기능이 부족합니다. 가장 주목할 만하게, 그들은 표적과 관련되었던 알려진 유형 변환기를 지원하지 않는다. MacDonald, Pro WPF in C# 2008, p. 이것이 cwap이 정확하게 응답하여 아마도 형식 변환기를 만들고이를 사용자 지정 단추의 컨트롤 템플릿에서 구체적으로 참조해야하는 이유입니다.

그러나 사용자 지정 컨트롤의 ImagePath 속성에 컨트롤 템플릿을 바인딩 할 때 TemplateBinding을 사용할 필요가 없습니다. 일반 Binding 객체를 사용할 수 있습니다.템플릿에서 ImageControl 보면

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

, 당신은 변화를 볼 수 있습니다 여기 내 사용자 지정 컨트롤의 템플릿에 대한 수정 마크 업입니다. 동일한 개체의 RelativeSource 속성에 유의하십시오. 이 속성을 = {RelativeSource TemplatedParent}로 설정하면 TaskButton의 Window1 인스턴스에 상대 경로를 입력하고 사용자 지정 컨트롤에서 올바르게 해결할 수 있습니다.

그래서이 스레드를 연구하는 다른 사람들은 값 변환기를 건너 뛰고 단순히 Image 속성의 TemplateBinding에서 Binding으로 전환하는 것이 좋습니다.

MSDN WPF 포럼에서 비슷한 질문으로 this answer을 제공 한 Marco Zhou에게도 감사드립니다.

2

실제로 이러한 답변 중 어느 것도 맞지 않습니다.

{TemplateBinding ImagePath}{Binding Path=ImagePath, RelativeSource={RelativeSource TemplatedParent}}의 바로 가기에 불과하며 거의 완전 동일합니다.

또한 ImagePath에 문자열을 입력하면 응용 프로그램 성능에 영향을 미치지 만 올바르게 ImageSource으로 해결됩니다. 실제 문제는 테스트를 위해 xaml에 제공된 ImagePath="Resources\calendar.png"의 상대 및 절대 이미지 경로와 관련이 있습니다. 이것은 컴파일러가 경로를 정의 할 때/대신 /를 사용하기 때문에 제공된 경로가 절대적이라고 생각하게합니다.

긴 형식의 바인딩이 작동하고 바로 가기가 작동하지 않는 이유는 제공된 이미지 (Resources \ calendar.png)의 원본이 절대 경로가 아닌 상대 경로임을 컴파일러에 제공하는 단서를 제공하기 때문입니다 따라서 이미지가 발견되고 바인딩이 작동합니다. 바인딩을 디버깅하면 바로 가기가 제공된 문자열을 이미지 소스로 해석하려고 시도하지만 "Resources \ calendar.png"파일을 찾을 수 없음을 알 수 있습니다. 이미지에 전체 URI를 제공하면 "C:\...\Resources\calendar.png" 또는 "/application;component/Resources/calendar.png" 그러면 이미지가 발견되고 바인딩이 해결됩니다.

이 점은 최종 편집에 리소스로 컴파일 된 이미지가 아닌 외부 소스에서 이미지를 참조하려고 할 때 매우 중요합니다.

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(); 
     } 
    } 

2 결합 부모의 문자열 properety에 이미지 소스를이 XAML 같은 (난 "태그"속성 사용) :

<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}}"/> 
관련 문제