5

UIに2つのデータグリッドが表示されています。データグリッド1で特定の行を選択すると、データグリッド1の詳細をデータグリッド2に表示したいと思います。データベースからデータグリッドデータを入力しています。これが2つのデータベーステーブル構造です。

注:両方のテーブルは、データベース内のpersonidによってマップされます

人物テーブル

PersonDetailsテーブル

これが私が試したこれまでのコードです

Baseclass.cs

public class Baseclass
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void SetProperty<T>(ref T member, T value, [CallerMemberName] string propertyName = null)
    {
        member = value;
        this.RaiseNotification(propertyName);
    }

    protected void RaiseNotification(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

person.cs

public class person : Baseclass
{

    private int personID;
    public int PersonID
    {
        get { return personID; }
        set { this.SetProperty<int>(ref this.personID, value); }
    }

    private string firstName;
    public string FirstName
    {
        get { return firstName; }
        set { this.SetProperty<string>(ref this.firstName, value); }
    }

    private string lastName;
    public string LastName
    {
        get { return lastName; }
        set { this.SetProperty<string>(ref this.lastName, value); }
    }

    Model _personModel = new Model();
    private ObservableCollection<person> _person = new ObservableCollection<person>();
    public ObservableCollection<person> Getpersons
    {
        get { return _person; }
        set { _person = value; OnPropertyChanged("GetPersons"); }
    }

    public person()
    {
        initializeload();
    }

    private void initializeload()
    {
        try
        {
            DataTable table = _personModel.getData();

            for (int i = 0; i < table.Rows.Count; ++i)
                Getpersons.Add(new person
                {
                 PersonID = Convert.ToInt32(table.Rows[i][0]),
                 FirstName = table.Rows[i][1].ToString(),
                 LastName = table.Rows[i][2].ToString(),
                });
        }

        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyname)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyname));
    }

    public class Model
    {
        public DataTable getData()
        {
            DataTable ndt = new DataTable();
            SqlConnection sqlcon = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
            sqlcon.Open();
            SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM [Person].[dbo].[persons]", sqlcon);
            da.Fill(ndt);
            da.Dispose();
            sqlcon.Close();
            return ndt;
        }
    }

}

PersonDetailクラス

public  class PersonDetails : Baseclass
{
    private int personID;
    public int PersonID
    {
        get { return personID; }
        set { this.SetProperty<int>(ref this.personID, value); }
    }

    private string address;
    public string Address
    {
        get { return address; }
        set { this.SetProperty<string>(ref this.address, value); }
    }

    private string pos;
    public string Position
    {
        get { return pos; }
        set { this.SetProperty<string>(ref this.pos, value); }
    }

    DetailsModel _detailModel = new DetailsModel();
    private ObservableCollection<PersonDetails> _details = new ObservableCollection<PersonDetails>();
    public ObservableCollection<PersonDetails> GetDetails
    {
        get { return _details; }
        set { _details = value; OnPropertyChanged("GetDetails"); }
    }
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyname)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyname));
    }

    public PersonDetails()
    {
        initializeload();
    }

    private void initializeload()
    {
        try
        {
            DataTable table = _detailModel.getData();

            for (int i = 0; i < table.Rows.Count; ++i)
                GetDetails.Add(new PersonDetails
                {
                    PersonID = Convert.ToInt32(table.Rows[i][0]),
                    Address = table.Rows[i][1].ToString(),
                    Position = table.Rows[i][2].ToString(),                        
                });
        }

        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
    public class DetailsModel
    {
        public DataTable getData()
        {
            DataTable ndt = new DataTable();
            SqlConnection sqlcon = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
            sqlcon.Open();
            SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM [Person].[dbo].[personDetails]", sqlcon);
            da.Fill(ndt);
            da.Dispose();
            sqlcon.Close();
            return ndt;
        }
    }
}

MainViewModel.cs

    public class MainViewModel : Base, INotifyPropertyChanged
{
    public MainViewModel()
    {
    }

    private ObservableCollection<person> personValues;
    public ObservableCollection<person> Persons
    {
        get { return personValues; }
        set
        {
            this.SetProperty<ObservableCollection<person>>(ref this.personValues, value);
        }
    }

    private ObservableCollection<PersonDetails> detailsValues;
    public ObservableCollection<PersonDetails> Details
    {
        /* This is correct below ?? I have an error as 
        'PersonDemo.MainViewModel' does not contain a definition for 'GetDetails' and no extension method 'GetDetails' accepting a first argument of type 'PersonDemo.MainViewModel' could be found (are you missing a using directive or an assembly reference?)*/
        get { return this.GetDetails(this.Selectedperson.PersonID); }
    }

    private person selectedValue;
    public person Selectedperson
    {
        get { return selectedValue; }
        set
        {
            this.SetProperty<person>(ref this.selectedValue, value);
            this.RaiseNotification("Details");
        }
    }


}

XAML

  <Grid>
  <DataGrid Margin="100,20,116,211" ItemsSource="{Binding Persons}" SelectedItem="{Binding Selectedperson}"  />
  <DataGrid Margin="100,130,116,101" ItemsSource="{Binding Details}" />
  </Grid>

誰かがMainViewModelの作成を進めるのを手伝ってもらえますか?私は数週間からここで立ち往生しています。

4

2 に答える 2

7

INotifyPropertyChangedまず、基本クラスのインターフェイスを使用することをお勧めします。たぶんあなたはそれを使って、サンプルコードにそれを書くのを忘れます。MVVMパターンでこれを行うには、両方のデータグリッドにViewModelを実装する必要があります。この例BothGridViewModelではそれを呼び出しましょう。必要に応じて呼び出すことができます。次に、このビューモデルでは、すべての人のコレクションが必要です。これを呼び出します。次に、タイプAllPersonのプロパティが必要です。Personグリッドに選択した人がいる場合は、それを呼び出しますSelectedPerson。次のようになります。

public class BothGridViewModel:INotifyPropertyChanged
{
    ...
    public ObservableCollection<Person> AllPersons {...}
    public Person SelectedPerson {...}
    ...
}

必要なのは、ビューのDataContextに設定することだけです。そしてバインディング:

<YourView DataContext={Binding SomeBothGridViewModelClass}>
    <Grid>
     <DataGrid Margin="100,20,116,211" ItemsSource="{Binding AllPersons}" SelectedItem="{Binding SelectedPerson}"  />
     <DataGrid Margin="100,130,116,101" ItemsSource="{Binding SelectedPerson.Getpersons}" /> <!--Or some SelectedPerson.PersonDetails.GetDetails-->
  </Grid>
</YourView DataContext={Binding SomeBothGridViewModelClass}>

これはあなたが望むものを作るための良いビューモデル構造だと思います。これがお役に立てば幸いです...


編集


これで、2つのデータベーステーブルがあります。1つはメインプロパティ用で、もう1つは詳細用です。これを行うには2つの良い方法があります。1)1つ目は、詳細のコレクションを持っていない人ごとに2番目のデータグリッドが必要であるとは思わないことです。代わりに、グリッドやその他のコントロールを使用してプロパティを表示できます。また、その人のビューモデルを実装する必要があると思います。たとえば、次のようになります。

public class PersonViewModel:INotifyPropertyChanged
{
     public string FirstName {...}
     public string LastName {...}
     //Other properties

     public PersonDetails Details {...}
}

次に、グリッドで、アイテムのソースをコレクションにPersonViewModelバインドしてから、グリッドの選択したアイテムにバインドすることができます。たとえば、次のようになります。

<Grid>
    <DataGrid x:Name="dataGrid" ItemsSource={Binding AllPersonViewModels}/>
    ...
    <!--Then some combo box, text block or text box binding to a property of the selected item's details-->
          ...
          <TextBox Text={Binding SelectedItem.Details.Address, ElementName=dataGrid}/>
          ...
<Grid>

2)私ができると思う2番目の方法は、同じデータグリッド内のすべてのデータを表示することです。PersonViewModelこのためには、次のようにクラスを行う必要があります。

public class PersonViewModel:INotifyPropertyChanged
{
     public string FirstName {...}
     public string LastName {...}
     //Other properties

     //Then the Details properties
     public string Address {...}
     //...
     //Note this class is like a wrapper for person, and person details
}

この方法は少し簡単ですが、アクセスを介して不要なデータベースが発生する可能性があります。


編集2


あなたのコードを見た後、私はそれについていくつかのことを言わなければなりません:で、私たちはWpfにいるので、代わりにを使用する必要がPersonViewModelあります。他のこととして、リポジトリパターンを使用して、実際にはすべてのDB通信を配置する場所と場所を作成する必要があります。これはある意味でリポジトリですが、今では変更する必要はありません。仕事。ここでは、のコードを示します。SelectedPersonDetailプロパティを持つように指定しました。このように、ビューでバインディングを作成するだけです。PersonDetailViewModelDispatcherTimerTimerPersonRepositoryPersonDetailRepositoryPersonViewModelPersonDetailViewModelMainViewModel

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using tryout13022013.PersonViewModels;
using System.ComponentModel;
using tryout13022013.DetailsViewModel;
using tryout13022013.PersonModel;

namespace tryout13022013
{
    public class MainViewModel
    {
        private PersonViewModel _subPerson = new PersonViewModel();
        public PersonViewModel SubPerson
        {
            get 
            {
                return _subPerson;
            }
            set
            {
                if (_subPerson != value)
                {
                    _subPerson = value; OnPropertyChanged("SubPerson");

                }
            }
        }


        private PersonDetailsViewModel _subDetail = new PersonDetailsViewModel();
        public PersonDetailsViewModel SubDetail
        {
            get { return _subDetail; }
            set 
            {
                _subDetail = value; OnPropertyChanged("SubDetail");
            }

        }

        private Person _selectedPerson;
        public Person SelectedPerson
        {
            get { return _selectedPerson; }
            set {
                if (_selectedPerson != value)
                {
                    _selectedPerson = value;
                    OnPropertyChanged("SelectedPerson");
                    OnPropertyChanged("SelectedPersonDetail");  //In this way when Change the Selected Person, the Selected Detail will be changed again...
                    //if (this.SelectedPerson != null && this.SubDetail != null)
                    //{
                       // I dont know how to call the PersonDetailsViewModel class like a method here in order to load its data. kindly help
                       //this.SubDetail.MethodforLoadingPersonDetails(this.SelectedPerson);
                    //}
                }
            }

        }

        public PersonDetails SelectedPersonDetail
        {
            get
            {
                if (SubDetail == null || SelectedPerson ==null)
                    return  null;
                return SubDetails.DetailsData.FirstOrDefault(detail => detail.PersonID == SelectedPerson.PersonID);
            }           

        }


        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyname)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyname));
        }
    }
}

これは、ビューで作成できるバインディングのインスタンスです。この場合は、2番目のグリッドでアイテムを選択します。

<Window x:Class="tryout13022013.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:person="clr-namespace:tryout13022013.PersonViewModels"
    xmlns:details="clr-namespace:tryout13022013.DetailsViewModel"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <DataGrid ItemsSource="{Binding SubPerson.PersonData}"  SelectedItem="{Binding SelectedPerson, Mode=TwoWay}"
        AutoGenerateColumns="False" Height="77" HorizontalAlignment="Left"
        Margin="101,26,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="auto" >
        <DataGrid.DataContext>
            <person:PersonViewModel/>
        </DataGrid.DataContext>
        <DataGrid.Columns>
            <DataGridTextColumn Header="ID" Width="auto" Binding="{Binding PersonID}"/>
            <DataGridTextColumn Header="First Name" Width="auto" Binding="{Binding FirstName}"/>
            <DataGridTextColumn Header="Last Name" Width="auto" Binding="{Binding LastName}"/>     
        </DataGrid.Columns>
    </DataGrid>


    <DataGrid ItemsSource="{Binding SubDetail.DetailsData}" 
        AutoGenerateColumns="False" Height="77" HorizontalAlignment="Left" 
        Margin="101,135,0,0" Name="dataGrid2" VerticalAlignment="Top" Width="255" SelectedItem="{Binding SelectedPersonDetail, Mode=OneWayToSource}">
        <DataGrid.DataContext>
            <details:PersonDetailsViewModel/>
        </DataGrid.DataContext>
        <DataGrid.Columns>
            <DataGridTextColumn Header="ID" Width="auto" Binding="{Binding PersonID}"/>
            <DataGridTextColumn Header="Address" Width="auto" Binding="{Binding Address}"/>
            <DataGridTextColumn Header="Position" Width="auto" Binding="{Binding Description}"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

私はそれを忘れました、あなたはへのバインディングを作る必要があります、SubPerson.PersonDataそしてSubDetail.DetailsData、これらはコレクションです。見てみな...

于 2013-02-11T19:58:10.127 に答える
4

WPFルームでBuba1947とチャットした結果、彼女はデータベースに1対1の関係分割テーブルを持っており、分割データグリッドにそのように表示しようとしていると結論付けました。

私は彼女に&テーブルのPersonViewModel上に作成することを提案したので、彼女は2つをバインドするプロパティの下に1つだけ含まれます。PersonPersonDetailsMainViewModelObservableCollection<PersonViewModel>PersonsDataGrids

したがって、MainViewModel.cs(DataContext)には次のものがあります。

private ObservableCollection<PersonViewModel> personValues; 
public ObservableCollection<PersonViewModel> Persons 
{ 
    get { return personValues; } 
    set { this.SetProperty<ObservableCollection<PersonViewModel>>(ref this.personValues, value); } 
} 

データアダプタが変更され、内部結合を使用してデータを取得します。関連するクエリは、これに沿ったものです(上記のPersonsプロパティを埋めます)。

"SELECT * FROM [Person].[dbo].[persons] INNER JOIN [Person].[dbo].[personDetails] ON [Person].[dbo].[persons].[Id] = [Person].[dbo].[personDetails].[Id]"

次にCollectionViewSource、XamlのPersonsにaをバインドします。

<Window.Resources>
    <CollectionViewSource x:Key="PersonsData" Source={Binding Persons} />
</Window.Resources>

DataGrids個々の列でこれにバインドします。

<DataGrid ItemsSource={Binding Source={StaticResource PersonsData}} AutoGenerateColumns="false">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Person Id" Content={Binding PersonId} />
        <DataGridTextColumn Header="First Name" Content={Binding FirstName} />
        <DataGridTextColumn Header="Last Name" Content={Binding LastName} />
    </DataGrid.Columns>
</DataGrid>

<DataGrid ItemsSource={Binding Source={StaticResource PersonsData}} AutoGenerateColumns="false">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Person Id" Content={Binding PersonId} />
        <DataGridTextColumn Header="Address" Content={Binding Address} />
        <DataGridTextColumn Header="Position" Content={Binding Position} />
    </DataGrid.Columns>
</DataGrid>

注:VSが手元にないため、ここにタイプミスがある可能性があります。何かを修正する必要がある場合はお知らせください。私はこれらすべてをメモリから書きました。

于 2013-02-12T11:51:40.307 に答える