2017-11-16 23 views
1

2つの異なるウィンドウで使用できるwpfコントロールがあります。コントロールには、コントロールをホストしているウィンドウに関係なく、同じクラスのObservableCollectionによって供給されるListViewが含まれています。ListViewの表示列をDependencyPropertyに基づいて変更します

あるウィンドウでは、特定の列のセットを表示し、別のウィンドウでは異なるセットの列を表示することができます。

私が達成しようとしていることの簡単な例が含まれています。この例では、xmlはUserControlではなくウィンドウに含まれています。ここで

は、ウィンドウとその2つのリストビューを定義するXAMLです:

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

これは私のささいなのviewmodel、およびレコードクラスです:次世代へ

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で前後に変更すると、プログラムは1つの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

あなたは異なる特性を持つコントロールの新しい、ネストされたインスタンスを作成し、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> 

列挙列のセットを指定するための1つの選択肢です。また、列名のコレクション、または分割されるいくつかの特殊文字( "Name | Food | Gas | Lodging")で区切られた単一の文字列を与えてから、UserControlで何かを実行して列のコレクションを作成することもできますその上に。

しかし、あらかじめ定義された列のコレクション、カスタム幅などを使用している場合、これはすばやく簡単で、ジョブを実行します。あなたはこれで賢明になる必要はありません。

関連する問題