programing

WPF 데이터를 인터페이스에 바인딩하고 실제 객체가 아님 - 캐스팅이 가능합니까?

mailnote 2023. 5. 26. 22:07
반응형

WPF 데이터를 인터페이스에 바인딩하고 실제 객체가 아님 - 캐스팅이 가능합니까?

예를 들어 다음과 같은 인터페이스가 있습니다.

public interface ISomeInterface
{
...
}

또한 이 인터페이스를 구현하는 몇 개의 클래스가 있습니다.

public class SomeClass : ISomeInterface
{
...
}

이제 사용자 지정 데이터 템플릿을 사용하여 ISome 인터페이스의 항목을 나열하는 WPF ListBox를 가지고 있습니다.

데이터 바인딩 엔진은 분명히 (내가 알아낼 수 있었던) 인터페이스 속성에 바인딩하는 것을 허용하지 않을 것입니다. 개체가 SomeClass 개체임을 확인하고 SomeClass가 바인딩된 속성을 비인터페이스 속성으로 사용할 수 있는 경우에만 데이터가 표시됩니다.

모든 개체가 SomeClass가 아닌 ISomeInterface인 것처럼 작동하도록 DataTemplate에 지시하려면 어떻게 해야 합니까?

감사합니다!

명시적으로 구현된 인터페이스 멤버에 바인딩하려면 괄호만 사용하면 됩니다.예:

암시적:

{Binding Path=MyValue}

명시적:

{Binding Path=(mynamespacealias:IMyInterface.MyValue)}

Beatriz Costa - MSFT의 Microsoft 포럼 답변은 읽을 가치가 있습니다.

얼마 전 데이터 바인딩 팀에서 인터페이스 지원 추가에 대해 논의했지만 좋은 설계가 나오지 않아 구현하지 못했습니다.문제는 인터페이스가 객체 유형과 같은 계층 구조를 가지고 있지 않다는 것입니다.데이터 소스가 두 가지를 모두 구현하는 시나리오를 고려합니다.IMyInterface1그리고.IMyInterface2리소스에는 두 인터페이스 모두에 대한 DataTemplate가 있습니다. 어떤 DataTemplate를 선택해야 한다고 생각하십니까?

객체 유형에 대한 암시적 데이터 템플릿을 수행할 때, 우리는 먼저 다음을 찾으려고 합니다.DataTemplate정확한 유형에 대해서는 부모, 조부모 등에 대해서는.우리가 적용할 유형의 순서는 매우 잘 정의되어 있습니다.인터페이스에 대한 지원을 추가하는 것에 대해 이야기할 때, 우리는 반사를 사용하여 모든 인터페이스를 찾아 유형 목록의 끝에 추가하는 것을 고려했습니다.우리가 직면한 문제는 유형이 여러 인터페이스를 구현할 때 인터페이스의 순서를 정의하는 것이었습니다.

우리가 명심해야 할 또 다른 점은 반사 비용이 그리 싸지 않다는 것이고, 이것은 이 시나리오에 대한 우리의 성과를 약간 감소시킬 것입니다.

그렇다면 해결책은 무엇일까요?이 모든 것을 XAML에서 할 수는 없지만 약간의 코드로 쉽게 할 수 있습니다.ItemTemplateSelectorItemsControl어떤 것을 선택하는 데 사용할 수 있습니다.DataTemplate각 항목에 사용할 수 있습니다.SelectTemplate템플릿 선택기에 대한 메서드, 템플릿을 만들 항목을 매개 변수로 받습니다.하고, 어 인 고 반 수 있 환 습 니 다 할 다 을 음 하 확 인 지 터 구 스 를 페 이 는 현 하 ▁the 다DataTemplate잘 어울리네요.

간단히 말해 DataTemplate는 인터페이스를 지원하지 않습니다(다중 상속, 명시적 v. 암시적 등).이 문제를 해결하는 방법은 기본 클래스를 확장하여 데이터 템플릿을 전문화/일반화하는 것입니다.이는 다음과 같은 적절한 솔루션을 의미합니다.

public abstract class SomeClassBase
{

}

public class SomeClass : SomeClassBase
{

}

<DataTemplate DataType="{x:Type local:SomeClassBase}">
    <!-- ... -->
</DataTemplate>

다른 방법이 있습니다.데이터 템플릿에 키를 설정하고 항목 템플릿에서 해당 키를 참조합니다.다음과 같이:

<DataTemplate DataType="{x:Type documents:ISpecificOutcome}"
              x:Key="SpecificOutcomesTemplate">
    <Label Content="{Binding Name}"
           ToolTip="{Binding Description}" />
</DataTemplate>

그런 다음 템플릿을 사용할 위치별로 다음과 같이 참조합니다.

<ListBox ItemsSource="{Binding Path=SpecificOutcomes}"
         ItemTemplate="{StaticResource SpecificOutcomesTemplate}"
         >
</ListBox>

렌더링

더미보이가 제안한 답은 최고의 답입니다(토피모에 투표해야 합니다).설계자가 좋아하지 않는 문제가 있지만("Object null을 PropertyPath의 액세스 매개 변수로 사용할 수 없습니다." 오류가 발생했습니다.) 좋은 해결 방법이 있습니다.이 문제를 해결하려면 데이터 템플릿에서 항목을 정의한 다음 템플릿을 레이블 또는 다른 내용 컨트롤로 설정합니다.예를 들어, 저는 다음과 같은 이미지를 추가하려고 했습니다.

<Image Width="120" Height="120" HorizontalAlignment="Center" Source="{Binding Path=(starbug:IPhotoItem.PhotoSmall)}" Name="mainImage"></Image>

하지만 그것은 계속해서 저에게 같은 오류를 주었습니다.솔루션은 레이블을 만들고 데이터 템플릿을 사용하여 내 컨텐츠를 표시하는 것이었습니다.

<Label Content="{Binding}" HorizontalAlignment="Center" MouseDoubleClick="Label_MouseDoubleClick">
    <Label.ContentTemplate>
        <DataTemplate>
            <StackPanel>
                <Image Source="{Binding Path=(starbug:IPhotoItem.PhotoSmall)}" Width="120" Height="120" Stretch="Uniform" ></Image>
            </StackPanel>
        </DataTemplate>
    </Label.ContentTemplate>
</Label>

이것도 단점이 있지만 저에게는 꽤 효과가 있는 것 같습니다.

참고: 인터페이스 속성이 경로 내에 있는 경우에도 이와 같은 복잡한 다중 요소 경로를 사용할 수 있습니다.

 <TextBlock>
    <TextBlock.Text>
        <Binding Path="Packages[0].(myNamespace:IShippingPackage.ShippingMethod).CarrierServiceCode"/>
    </TextBlock.Text>
 </TextBlock>

으로 직로으적접면아와 함께.Binding지시의

 <TextBlock Text="{Binding Path=Packages[0].(myNamespace:IShippingPackage.ShippingMethod).CarrierServiceCode}"/>

또는 인터페이스의 여러 속성을 사용할 때 로컬로 DataContext를 재정의하여 코드를 보다 쉽게 읽을 수 있도록 할 수 있습니다.

 <StackPanel DataContext={Binding Path=Packages[0].(myNamespace:IShippingPackage.ShippingMethod)}">
    <TextBlock Text="{Binding CarrierName}"/>
    <TextBlock Text="{Binding CarrierServiceCode}"/>
  </StackPanel>

팁: 실수로 다음과 같은 결과를 초래하지 않도록 주의하십시오.)}경로 식의 끝에 있습니다.복사/붙여넣기 오류가 계속 발생합니다.

Path="(myNameSpace:IShippingPackage.ShippingMethod)}"


반드시 사용하십시오.Path=

명시적으로 사용하지 않을 경우Path=그러면 바인딩을 구문 분석하지 못할 수 있습니다.일반적으로 저는 다음과 같은 것을 쓸 것입니다.

Text="{Binding FirstName}"

대신에

Text="{Binding Path=FirstName}"

하지만 더 복잡한 인터페이스 바인딩을 사용하면Path=했습니다.

System.ArgumentNullException: Key cannot be null.
Parameter name: key
   at System.Collections.Specialized.ListDictionary.get_Item(Object key)
   at System.Collections.Specialized.HybridDictionary.get_Item(Object key)
   at System.ComponentModel.PropertyChangedEventManager.RemoveListener(INotifyPropertyChanged source, String propertyName, IWeakEventListener listener, EventHandler`1 handler)
   at System.ComponentModel.PropertyChangedEventManager.RemoveHandler(INotifyPropertyChanged source, EventHandler`1 handler, String propertyName)
   at MS.Internal.Data.PropertyPathWorker.ReplaceItem(Int32 k, Object newO, Object parent)
   at MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(Int32 k, ICollectionView collectionView, Object newValue, Boolean isASubPropertyChange)

즉, 다음과 같이 하지 마십시오.

<TextBlock Text="{Binding Packages[0].(myNamespace:IShippingPackage.ShippingMethod).CarrierServiceCode}"/>

언급URL : https://stackoverflow.com/questions/327984/wpf-databinding-to-interface-and-not-actual-object-casting-possible

반응형