1

多数の比較的複雑なリスト ビューを使用する WPF を使用して MVVM アプリケーションを構築しています。リスト ビューがバインドするコレクションが、基になるモデル オブジェクトのリストではなく、View-Model オブジェクトのコレクションであるというパターンを採用しました。このようなコード

var itemsSource = messages.Select(i => new MessageViewModel(i));

この場合、リスト ビューはMessageオブジェクトのリストをユーザーに表示しています。これは問題なく機能しますが、特にコレクションの変更イベントを処理する場合はかなり扱いにくいです。

ここで、アプリケーションの別の場所でこの ListView を再利用して、一貫した方法でユーザーに別のメッセージ リストを表示したいと考えています。表示されるオプションは次のとおりです。

  • タイプのコレクションから派生しListView、データをバインドするリスト ビューを作成します。MessageViewModel
  • Message内部的に構築されたコレクションにバインドされたリスト ビュー データを含むか、そこから派生したオブジェクトのコレクションにデータバインドするコントロールを作成します。MessageViewModel

最初のオプションでは、コントロールを使用するすべてのユーザーが、コレクションを構築および維持する不格好なコードを実行する必要がありますMessageViewModel。2 番目のオプションでは、このビュー モデル コレクションのメンテナンスをカプセル化しますがListView、基になるアイテムをコレクションを元のMessage型に変換できるようにします。

同様の再利用性の問題を抱えている同様のリストビューが多数あります。

これらのビューを MVVM アプリケーションで再利用できるようにする WPF ItemsControl ベースのビューを処理するためのより良い方法はありますか?

4

1 に答える 1

1

再利用したいものが 2 つあります。

  1. MessageViewModel のコレクションを公開して、このコレクションを ListView の itemsSource にバインドできるようにします。
  2. (オプション) 特定のリスト ビューに、再利用したいスタイル (またはコンテンツ プレゼンター、またはデータ テンプレート) があります。この部分には、コード ビハインド、トリガーなどが含まれる場合もあります。

2 つを混ぜてはいけません。

#2 は、リスト ビューまたはデータ テンプレートに適用するスタイルで実現できます。個人的には、専用のクラスを MessageViewModel のコレクションとして定義し、データ テンプレートで TargetType をそのクラスに設定するのが好きです。

#1 は Collection、INotifyCollecitonChanged、INotifyPropertyChanged を実装するクラスです。最善の (そして最も簡単な) 方法は、単に ObservableCollection をラップすることです。構築では、Select メソッドを実行します。次に、簿記の方法があります。

いくつかのサンプル(動作中!)コードの下。ビューにはコードビハインドがないことに注意してください。2 つのリストをグリッドに 2 回配置しました。ContentControl と DataTemplate の使用は私のスタイルです。これを行う方法は他にもたくさんあります。

======= Model.cs ====

using System;

namespace SO
{
    class Message
    {
        public string from { get; set; }
        public string to { get; set; }
        public string subject { get; set; }
        public DateTime received { get; set; }
    }
}

======= ViewModel.cs ====

using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace SO
{
    class MessageVM : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private Message m_model;

        public MessageVM( Message model ) {
            m_model = model;
        }

        private void raize( string prop ) {
            PropertyChanged( this, new PropertyChangedEventArgs("prop") );
        }

        public string from {
            get { return m_model.from; }
            set { m_model.from = value; raize("from"); }
        }

        public string to {
            get { return m_model.to; }
            set { m_model.subject = value; raize("to") ); }
        }

        public string subject {
            get { return m_model.subject; }
            set { m_model.subject = value; raize("subject") ); }
        }

        public DateTime received {
            get { return m_model.received; }
            set { m_model.received = value; raize("recieved") ); }
        }

    }

    class FolderVM : ObservableCollection<MessageVM>
    {
        public FolderVM( IEnumerable<Message> models )
            :base( models.Select( msg => new MessageVM(msg) ) )
        {
        }
    }


    class SampleData
    {
        //static public FolderVM folder { get; set; }

        static public FolderVM folder;



        static SampleData( )
        {
            // create a sample model
            List<Message> model = new List<Message>();
            model.Add( new Message { from = "Bill", to = "Steve", subject = "Resusable Items Control", received = DateTime.Now.AddDays(-4) } );
            model.Add( new Message { from = "Steve", to = "Bill", subject = "Resusable Items Control", received = DateTime.Now.AddDays( -3 ) } );
            model.Add( new Message { from = "Bill", to = "Jeff", subject = "stack", received = DateTime.Now.AddDays( -2 ) } );

            // initialize the view model
            folder = new FolderVM( model );
        }
    }
}

======= MainWindow.xaml ====

<Window x:Class="Paf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:src="clr-namespace:SO"
        Title="MainWindow" Height="350" Width="525"
        >

    <Window.Resources>
        <DataTemplate DataType="{x:Type src:FolderVM}">
            <ListView ItemsSource="{Binding}">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="from" Width="80" DisplayMemberBinding="{Binding Path=from}" />
                        <GridViewColumn Header="to" Width="80" DisplayMemberBinding="{Binding Path=to}" />
                        <GridViewColumn Header="subject" Width="200" DisplayMemberBinding="{Binding Path=subject}" />
                        <GridViewColumn Header="received" Width="160" DisplayMemberBinding="{Binding Path=received}" />
                    </GridView>
                </ListView.View>
            </ListView>
        </DataTemplate>        
    </Window.Resources>


    <StackPanel>
        <ContentControl Content="{Binding Source={x:Static src:SampleData.folder}}" />
        <ContentControl Content="{Binding Source={x:Static src:SampleData.folder}}" />
    </StackPanel>

</Window>
于 2013-02-25T18:43:03.183 に答える