2016-09-03 4 views
0

WPF 응용 프로그램에서 작업 중이며 최근에는 재사용이 가능하도록 User Controls을 만들었습니다.여러 상자 형식의 컬렉션에 대해 다시 사용할 수 있도록 UserControl의 콤보 상자 ItemsSource를 일반화합니다.

나는 두 개의 User ControlsInputUCComboBoxUC을 가지고 있습니다. 둘 다 LabelTextBox이고 LabelComboBox입니다. 필요한 종속성 속성을 정의하여 InputUC을 성공적으로 구현했습니다.

제가 직면 한 문제는 ComboBoxUC입니다. 내 응용 프로그램에서 Cities, Customers, Salesmen 및 다른 위치에있는 다른 엔티티를 표시해야하는 시나리오가 있습니다. 분명히 각 엔티티는 DisplayMemberPath, SelectedValuePath, SelectedValue 속성 및 ItemsSource 속성이 ComboBox 인 다른 유형의 Collection에 다른 속성 이름을 제공합니다.

인터넷에서 검색 한 적이 있지만 동일한 해결책을 찾지 못했습니다.

내가 노력하고 코드는 내가이 UserControl을 사용하고 ComboBoxUC.xaml.cs

public string ComboBoxLabel 
    { 
     get { return (string)GetValue(LabelProperty); } 
     set { SetValue(LabelProperty, value); } 
    } 

    public bool ComboBoxIsRequired 
    { 
     get { return (bool)GetValue(IsRequiredProperty); } 
     set { SetValue(IsRequiredProperty, value); } 
    } 

    public long ComboBoxValue 
    { 
     get { return (long)GetValue(ValueProperty); } 
     set { SetValue(ValueProperty, value); } 
    } 

    public bool ComboBoxIsEnabled 
    { 
     get { return (bool)GetValue(ValueEnabledProperty); } 
     set { SetValue(ValueEnabledProperty, value); } 
    } 

    public ObservableCollection<CityViewModel> ComboBoxItems 
    { 
     get { return (ObservableCollection<CityViewModel>)GetValue(ValueItems); } 
     set { SetValue(ValueItems, value); } 
    } 

    public string ComboBoxDisplayMemberPath 
    { 
     get { return GetValue(ValueDisplayMemberPath).ToString(); } 
     set { SetValue(ValueDisplayMemberPath, value); } 
    } 

    public string ComboBoxSelectedValuePath 
    { 
     get { return GetValue(ValueSelectedValuePath).ToString(); } 
     set { SetValue(ValueSelectedValuePath, value); } 
    } 

    public static readonly DependencyProperty LabelProperty = DependencyProperty.Register("ComboBoxLabel", typeof(string), 
     typeof(ComboBoxUC), new PropertyMetadata(string.Empty)); 

    public static readonly DependencyProperty IsRequiredProperty = DependencyProperty.Register("ComboBoxIsRequired", typeof(bool), 
      typeof(ComboBoxUC), new PropertyMetadata(false)); 

    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("ComboBoxValue", typeof(long), 
      typeof(ComboBoxUC), new FrameworkPropertyMetadata { BindsTwoWayByDefault = true, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); 

    public static readonly DependencyProperty ValueEnabledProperty = DependencyProperty.Register("ComboBoxIsEnabled", typeof(bool), 
      typeof(ComboBoxUC), new FrameworkPropertyMetadata { BindsTwoWayByDefault = false, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); 

    public static readonly DependencyProperty ValueItems = DependencyProperty.Register("ComboBoxItems", typeof(ObservableCollection<CityViewModel>), 
      typeof(ComboBoxUC), new FrameworkPropertyMetadata { BindsTwoWayByDefault = false, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); 

    public static readonly DependencyProperty ValueDisplayMemberPath = DependencyProperty.Register("ComboBoxDisplayMemberPath", typeof(string), 
      typeof(ComboBoxUC), new FrameworkPropertyMetadata { BindsTwoWayByDefault = false, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); 

    public static readonly DependencyProperty ValueSelectedValuePath = DependencyProperty.Register("ComboBoxSelectedValuePath", typeof(string), 
      typeof(ComboBoxUC), new FrameworkPropertyMetadata { BindsTwoWayByDefault = true, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); 

    public ComboBoxUC() 
    { 
     InitializeComponent(); 
    } 

Page 제어에서 코드 ComboBoxUC의 뒤에

ComboBox 제어

<ComboBox Name="valuesComboBox" 
      Grid.Column="1" 
      ItemsSource="{Binding ComboBoxItems}" 
      DisplayMemberPath="{Binding ComboBoxDisplayMemberPath}" 
      SelectedValuePath="{Binding ComboBoxSelectedValuePath}" 
      SelectedValue="{Binding ComboBoxValue}" 
      IsEnabled="{Binding ComboBoxIsEnabled}" 
      Style="{StaticResource ComboBox-Base}"> 
</ComboBox> 

ComboBoxUC.xaml의 코드입니다

<local:ComboBoxUC ComboBoxLabel="City" 
        ComboBoxIsRequired="True" 
        ComboBoxValue="{Binding CustomerViewModel.customer_city_id}" 
        ComboBoxItems="{Binding Cities}" 
        ComboBoxDisplayMemberPath="city_name" 
        ComboBoxSelectedValuePath="city_id" 
        ComboBoxIsEnabled="{Binding Flags.AddOrUpdate}"> 
</local:ComboBoxUC> 

이제 응용 프로그램의 여러 곳에서 xaml과 동일하게 사용할 것입니다. 각각의 경우에 다를 수 있습니다 일들은 다음과 같습니다

  • 도시
  • CITY_NAME
  • 내가 제대로 ComboBoxUC.xamlDataContext 현재 코드를 설정 한

을 CITY_ID CustomerViewModel.customer_city_id 내 UserControl에 대해 Collection (CityViewModel)의 한 유형에 대해 올바르게 작동합니다. CustomerViewModel, SalesmanViewModel 등의 다른 엔티티에 동일한 코드를 사용하고 분명히 다른 속성 이름을 사용하고 싶습니다.

나는 다음 코드를 일반화하고 싶습니다.

public ObservableCollection<CityViewModel> ComboBoxItems 
{ 
    get { return (ObservableCollection<CityViewModel>)GetValue(ValueItems); } 
    set { SetValue(ValueItems, value); } 
} 

public static readonly DependencyProperty ValueItems = DependencyProperty.Register("ComboBoxItems", typeof(ObservableCollection<CityViewModel>), 
       typeof(ComboBoxUC), new FrameworkPropertyMetadata { BindsTwoWayByDefault = false, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); 

나뿐만 아니라 object 유형의 Collection을 시도했지만 물론 object 유형 내 기관에서 가지고있는 특성이 없습니다.

나는이 지점에서 개발로 전진 할 수 없으므로 도움이 될 것입니다.

답변

2

사용자 정의 컨트롤의 컬렉션을 일반화함으로써 강력하게 형식화하려고하는 대신, 덜 강하게 입력해야합니다. 기억하라. 콤보 상자 자체의 ItemsSource는 단순히 '객체'유형이다.

ComboBoxUC가 IEnumerable 유형의 DependencyProperty를 노출시키고 ComboBox ItemsSource에 바인딩하도록 제안합니다. 그런 다음 DataTemplate 형식의 DependencyProperty를 노출하고 ComboBox의 ItemTemplate 속성에 바인딩합니다. 사용자 정의 컨트롤을 사용할 때 간단한 DataTemplate을 제공하여 DisplayMember 경로를 사용하는 대신 원하는 속성을 표시 할 수 있습니다. 당신이 ComboboxUC에시를 표시 할 때 예를 들어, 당신이 할 수 있습니다 : 당신이 절대적으로 대신 SelectedValuePath에 결합해야하는 경우

<local:ComboBoxUC ItemsSource="{Binding Cities}"> 
    <local.ComboBoxUC.ItemTemplate> 
    <DataTemplate> 
     <TextBlock Text="{Binding city_name}"/> 
    </DataTemplate> 
    </local:ComboBoxUC.ItemTemplate> 
</local:ComboBoxUC/> 

난 다음, 사용자 정의 컨트롤의 DependencyProperty에로 콤보 상자의 selectedItem을 노출하고 것 SelectedItem의 ValueConverter를 사용하십시오.

솔직히 말해서,이 사용자 컨트롤이 약간 OTT 인 것처럼 느껴집니다. 만약 당신이 얻는 것이 모두 라벨과 어떤 스타일 일 경우, 리소스 딕셔너리에서 컨트롤을 retemplating하고이 방식으로 사용할 각 콤보 박스에 템플릿을 적용하여 동일하게 할 수 있습니다.

+0

내 관심사는 DisplayMemberPath 속성뿐입니다. SelectedValuePath 및 SelectedValue 속성을 사용해야합니다. 그리고 각 속성에 대해 DataTemplate을 정의 할 수는 없습니다. 사용자 정의 컨트롤을 추가하는 동안이 긴 Item 템플릿을 내 Window/Page Xaml에 제공해야한다면이 사용자 컨트롤을 분리 할 수 ​​있습니다. –

+1

DataTemplates (제어 템플릿을 결정해야 함)는 리소스 사전에서 중앙에서 정의 할 수 있으므로 한 번 정의하면되므로 다음과 같이 사용할 수 있습니다. ibebbs

+0

예제를 제공해 줄 수 있습니까? –

-1

변경할 필요가있는 것은 @ibebbs가 지적한대로 ObservableCollection ~ IEnumerable의 유형입니다.

public IEnumerable ComboBoxItems 
{ 
    get { return (IEnumerable)GetValue(ValueItems); } 
    set { SetValue(ValueItems, value); } 
} 

public static readonly DependencyProperty ValueItems = DependencyProperty.Register("ComboBoxItems", typeof(IEnumerable), 
       typeof(ComboBoxUC), new FrameworkPropertyMetadata { BindsTwoWayByDefault = false, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); 

나 응용 프로그램을 통해 서로 다른 유형의 Collection와 심지어 다른 속성 이름과 같은 UserControl를 사용하는 것을 허용했다.

+0

_ "알아 냈어 ** 나 자신 ** ** 바꿀 필요가있는 것은 ObservableCollection의 유형이 IEnumerable **인데 ** @ibebbs는 **을 지적했다."_ - 그 중 하나를 읽고 나면 대답은 모순이다. 경계 표절 – MickyD

+0

본인의 의도는이 시나리오에서 어떤 문제가 내 문제를 해결했는지 명확하게 설명하는 것이 아니라 신용을 얻는 것이 었습니다. 부정적 득표에 관한 한, 그것은 나의 실수 였고 나는 그것을 제거했습니다. 그러나 여전히 @ibebbs 대답은 내 문제를 모두 해결하지 못했습니다. 나는 나의 대답에서 나의 이슈를 해결 한 특별한 것에 대답했다. 그것은 나의 의견으로는 표절이 아니다. –