2017-11-16 7 views
1

두 개의 다른 창에서 사용할 수있는 wpf 컨트롤이 있습니다. 컨트롤에는 컨트롤을 호스팅하는 창에 관계없이 같은 클래스의 ObservableCollection에 의해 제공되는 ListView가 포함됩니다.DependencyProperty를 기반으로 ListView의 표시된 열 변경

하나의 창에서 특정 열 집합을 표시하고 다른 창에는 다른 열 집합을 표시하려고합니다.

나는 성취하려는 것을 보여주는 간단한 예를 포함 시켰습니다. 이 예제의 목적을 위해 xml은 UserControl이 아닌 창에 포함되어 있습니다. 이

<Window x:Class="ListTest.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:ListTest" 
    mc:Ignorable="d" 
    Title="MainWindow" Height="350" Width="525"> 
<Window.DataContext> 
    <local:MainViewModel /> 
</Window.DataContext> 
<Window.Resources> 
    <ControlTemplate x:Key="listOne" TargetType="{x:Type ListView}"> 
     <ListView Margin="10,30,10,10" ItemsSource="{Binding MyList}"> 
      <ListView.View> 
       <GridView> 
        <GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" /> 
        <GridViewColumn Header="Food" Width="50" DisplayMemberBinding="{Binding Food}" /> 
       </GridView> 
      </ListView.View> 
     </ListView> 
    </ControlTemplate> 
    <ControlTemplate x:Key="listTwo" TargetType="{x:Type ListView}"> 
     <ListView Margin="10,30,10,10" ItemsSource="{Binding MyList}"> 
      <ListView.View> 
       <GridView> 
        <GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" /> 
        <GridViewColumn Header="Number" Width="120" DisplayMemberBinding="{Binding Number}" /> 
        <GridViewColumn Header="State" Width="50" DisplayMemberBinding="{Binding State}" /> 
       </GridView> 
      </ListView.View> 
     </ListView> 
    </ControlTemplate> 
</Window.Resources> 
<Grid> 
    <CheckBox x:Name="checkBox" Content="Complex" HorizontalAlignment="Left" 
       Margin="10,10,10,10" VerticalAlignment="Top" 
       IsChecked="{Binding IsComplex}"/> 
    <ListView Margin="10" Name="lvUsers" Template="{StaticResource listTwo}" /> 
</Grid> 

내 사소한 뷰 모델이며, 레코드 클래스 : 여기

는 윈도우와 두의 ListView 정의하는 XAML입니다

public class MyRecord 
{ 
    public MyRecord(string firstName, string food, int number, string state) 
    { 
     Name = firstName; 
     Food = food; 
     Number = number; 
     State = state; 
    } 

    public string Name { get; set; } 
    public string Food { get; set; } 
    public int Number { get; set; } 
    public string State { get; set; } 
} 

public class MainViewModel : ViewModelBase 
{ 
    private List<MyRecord> _recordList; 

    public MainViewModel() 
    { 
     _recordList = new List<MyRecord>(); 
     _recordList = new List<MyRecord>(); 
     _recordList.Add(new MyRecord("Lee", "pizza", 10, "ID")); 
     _recordList.Add(new MyRecord("Gary", "burger", 20, "UT")); 

     MyList = new ObservableCollection<MyRecord>(_recordList); 
    } 

    private ObservableCollection<MyRecord> _myList; 
    public ObservableCollection<MyRecord> MyList 
    { 
     get { return _myList; } 
     set 
     { 
      if (_myList != value) 
      { 
       _myList = value; 
       OnPropertyChanged(() => MyList); 
      } 
     } 
    } 

    private bool _isComplex = true; 
    public bool IsComplex 
    { 
     get { return _isComplex; } 
     set 
     { 
      if (_isComplex != value) 
      { 
       _isComplex = value; 
       OnPropertyChanged(() => IsComplex); 
      } 
     } 
    } 
} 

을 다음-에 xaml의 마지막 줄에는 하드 코드 된 템플릿 할당이 있습니다.

 <ListView Margin="10" Name="lvUsers" Template="{StaticResource listTwo}" /> 

xaml에서 앞뒤로 변경하면 프로그램에서 하나의 ListView 레이아웃을 표시하거나 오류없이 다른 프로그램을 표시합니다.

사용되는 레이아웃을 제어하는 ​​ViewModel의 속성을 설정할 수 있기를 원합니다.이 간단한 경우에는 선택한 ListView를 제어해야하는 확인란이 있습니다.

나는 가장 간단한 방법 인 트리거를 시도했지만 컴파일러를 행복하게 만드는 어떤 것도 발견하지 못했습니다.

의견을 보내 주시면 감사하겠습니다.

업데이트 : Ed Plunkett의 답변에 내 질문이 너무 힘들어 보였습니다. 나는 전체 ListView를 대체하고 싶지 않았고, 그 안에 어떤 열이 표시 되었는지만 제어했습니다. 코드의 일부를 추출하면 원래 코드 숨김으로 들어가서 전체 ListView를 바꾸지 않고 원래 원하는대로 동작하게됩니다. 체크 박스를 토글하면 샘플의 표시된 열이 이제 올바른 "보기"로 전환됩니다. 코드 숨김은 변경되지 않았으며 뷰 모델은 그대로 유지됩니다. 감사합니다 에드! 나는 내가 필요한 코드의 서브 세트를 보여 주었기 때문에 그의 대답을 받아 들였고, 진정한 질문이 무엇인지를 반영하도록 제목을 변경했다.

이 전체 개정 XAML입니다 :

<Window x:Class="AAWorkTest.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:ListTest" 
    mc:Ignorable="d" 
    Title="MainWindow" Height="350" Width="525"> 
<Window.DataContext> 
    <local:MainViewModel /> 
</Window.DataContext> 
<Grid> 
    <CheckBox x:Name="checkBox" Content="Complex" HorizontalAlignment="Left" 
       Margin="10,10,10,10" VerticalAlignment="Top" 
       IsChecked="{Binding IsComplex}"/> 
    <ListView ItemsSource="{Binding MyList}" Margin="10,30,10,30" Name="lvUsers"> 
     <ListView.Style> 
      <Style TargetType="ListView"> 
       <Style.Triggers> 
        <DataTrigger Binding="{Binding IsComplex}" Value="False"> 
         <Setter Property="View"> 
          <Setter.Value> 
           <GridView> 
            <GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" /> 
            <GridViewColumn Header="Food" Width="50" DisplayMemberBinding="{Binding Food}" /> 
           </GridView> 
          </Setter.Value> 
         </Setter> 
        </DataTrigger> 
        <DataTrigger Binding="{Binding IsComplex}" Value="True"> 
         <Setter Property="View"> 
          <Setter.Value> 
           <GridView> 
            <GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" /> 
            <GridViewColumn Header="Number" Width="120" DisplayMemberBinding="{Binding Number}" /> 
            <GridViewColumn Header="State" Width="50" DisplayMemberBinding="{Binding State}" /> 
           </GridView> 
          </Setter.Value> 
         </Setter> 
        </DataTrigger> 
       </Style.Triggers> 
      </Style> 
     </ListView.Style> 
    </ListView> 
</Grid> 

답변

1

당신은 서로 다른 특성을 가진 컨트롤의 새로운 중첩 인스턴스를 생성 하나를 사용하여 템플릿을 대체하여 컨트롤에 속성을 설정하지 마십시오 . WPF에서 ControlTemplate은 컨트롤이 표시되는 방법을 결정하고 컨트롤을 만들지 않습니다. 대신 속성을 설정하는 스타일로 속성을 설정합니다. 인 경우 ListView 템플릿을 변경하는 것이 좋습니다. 이렇게하면됩니다. 여기

(나는 물론, 그것을 위해 UserControl1 이름을 지정하지 않는 것이 좋습니다) 당신이 할 수있는 방법은 다음과 같습니다

UserControl1.xaml합니다.CS

public partial class UserControl1 : UserControl 
{ 
    public UserControl1() 
    { 
     InitializeComponent(); 
    } 

    public IEnumerable ItemsSource 
    { 
     get { return (IEnumerable)GetValue(ItemsSourceProperty); } 
     set { SetValue(ItemsSourceProperty, value); } 
    } 

    public static readonly DependencyProperty ItemsSourceProperty = 
     DependencyProperty.Register(nameof(ItemsSource), typeof(IEnumerable), typeof(UserControl1), 
      new PropertyMetadata(null)); 

    public ViewPurpose ViewPurpose 
    { 
     get { return (ViewPurpose)GetValue(ViewPurposeProperty); } 
     set { SetValue(ViewPurposeProperty, value); } 
    } 

    public static readonly DependencyProperty ViewPurposeProperty = 
     DependencyProperty.Register(nameof(ViewPurpose), typeof(ViewPurpose), typeof(UserControl1), 
      new PropertyMetadata(ViewPurpose.None)); 
} 

public enum ViewPurpose 
{ 
    None, 
    FoodPreference, 
    ContactInfo, 
    FredBarneyWilma 
} 

UserControl1.xaml

<UserControl 
    x:Class="WpfApp3.UserControl1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:local="clr-namespace:WpfApp3" 
    mc:Ignorable="d" 
    d:DesignHeight="300" d:DesignWidth="300"> 
    <Grid> 
     <ListView 
      ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource AncestorType=UserControl}}" 
      > 
      <ListView.Style> 
       <Style TargetType="ListView"> 
        <Style.Triggers> 
         <DataTrigger 
          Binding="{Binding ViewPurpose, RelativeSource={RelativeSource AncestorType=UserControl}}" 
          Value="FoodPreference" 
          > 
          <Setter Property="View"> 
           <Setter.Value> 
            <GridView> 
             <GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" /> 
             <GridViewColumn Header="Food" Width="50" DisplayMemberBinding="{Binding Food}" /> 
            </GridView> 
           </Setter.Value> 
          </Setter> 
         </DataTrigger> 
         <DataTrigger 
          Binding="{Binding ViewPurpose, RelativeSource={RelativeSource AncestorType=UserControl}}" 
          Value="ContactInfo" 
          > 
          <Setter Property="View"> 
           <Setter.Value> 
            <GridView> 
             <GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" /> 
             <GridViewColumn Header="Number" Width="120" DisplayMemberBinding="{Binding Number}" /> 
             <GridViewColumn Header="State" Width="50" DisplayMemberBinding="{Binding State}" /> 
            </GridView> 
           </Setter.Value> 
          </Setter> 
         </DataTrigger> 
        </Style.Triggers> 
       </Style> 
      </ListView.Style> 
     </ListView> 
    </Grid> 
</UserControl> 

사용 예 :

<StackPanel Orientation="Vertical"> 
    <local:UserControl1 
     ViewPurpose="FoodPreference" 
     ItemsSource="{Binding SomeCollectionOfWhatever}" 
     /> 
    <local:UserControl1 
     ViewPurpose="ContactInfo" 
     ItemsSource="{Binding DifferentCollectionOfWhatever}" 
     /> 
</StackPanel> 

열거 형은 열 집합을 지정하기위한 하나 개의 옵션입니다. 또한 열 이름의 모음 또는 분할 될 특수 문자 ("Name | Food | Gas | Lodging")로 구분 된 단일 문자열을 제공 한 다음 UserControl에서 무언가를 수행하여 열 기반으로 콜렉션을 만들 수 있습니다 그걸로.

그러나 사용자 정의 너비 등으로 미리 정의 된 열의 모음이 두 개 또는 세 개있는 경우이 작업은 빠르고 간단하며 작업을 수행합니다. 당신은 이것으로 너무 영리해질 필요가 없습니다.