2017-01-14 8 views
0

これは長いポストになるでしょうし、私はすでにタイトルを謝っています。私は自分の問題にラベルを付ける方法がわかりません。WPF with Entity Framework usercontrolのdatacontextを使ったCRUD操作

私の質問に直接関係はありませんが、Entity Framework(コードファースト)を使用してWPFアプリケーションを構築していることがわかります。どちらも私はかなり新しいです。私は簡単な問題、小さな問題のプロトタイプを次のように実行しました:

私は2つのモデル、FastFoodとPersonを持っています。人にはファーストフードのお気に入りがあり、ファーストフードには関連する人がいます(1対多)。

public class FastFood 
{ 
    /// <summary> 
    /// Id of entity 
    /// </summary> 
    public int Id { get; set; } 
    /// <summary> 
    /// Name of entity 
    /// </summary> 
    public string Name { get; set; } 

    /// <summary> 
    /// Person this food preference belongs to 
    /// </summary> 
    public Person Person { get; set; } 

    /// <summary> 
    /// Key value of person this food preference belongs to 
    /// </summary> 
    public int PersonId { get; set; } 

    /// <summary> 
    /// A fast food chain 
    /// </summary> 
    public FastFood() { } 
} 

public class Person 
{ 
    /// <summary> 
    /// Entity Id of this person 
    /// </summary> 
    public int Id { get; set; } 

    /// <summary> 
    /// Name of this person 
    /// </summary> 
    public string Name { get; set; } 

    /// <summary> 
    /// Fast food favorites for this person 
    /// </summary> 
    public IList<FastFood> Favorites { get; set; } 

    /// <summary> 
    /// A person 
    /// </summary> 
    public Person() { Favorites = new List<FastFood>(); } 
} 

私のテーブルはEFで完璧に作成され、すべてがうまくいきます。私の状況は次のとおりです(サンプルデータあり):

public FoodContext() : base("Food") 
    { 
     if(!Database.Exists()) 
      Database.SetInitializer(new FoodInit()); 
    } 
    /// <summary> 
    /// Table for person(s) 
    /// </summary> 
    public DbSet<Person> People { get; set; } 
    /// <summary> 
    /// Table for fast foods 
    /// </summary> 
    public DbSet<FastFood> FastFoods { get; set; } 
} 

class FoodInit : DropCreateDatabaseAlways<FoodContext> 
{ 
    protected override void Seed(FoodContext context) 
    { 
     Person Bill = new Person() { Name = "Bill" }; 
     FastFood GCoffee = new FastFood() { Name = "Gobias Industries" }; 
     FastFood BananaStand = new FastFood() { Name = "Banana Stand" }; 
     Bill.Favorites.Add(GCoffee); 
     Bill.Favorites.Add(BananaStand); 
     context.People.Add(Bill); 
    } 
} 

これはすべてうまくいきます。今すぐ簡単なGUIが来ます。

/// <summary> 
/// Interaction logic for MainWindow.xaml 
/// </summary> 
public partial class MainWindow : Window 
{ 
    public CollectionViewSource personViewSource; 
    public ObservableCollection<Person> People { get; set; } 

    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) 
     { 
      System.Windows.Data.CollectionViewSource personViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("personViewSource"))); 
      // Load data by setting the CollectionViewSource.Source property: 
      using(var context = new FoodContext()) 
      { 
       context.People.Include("Favorites").Load(); 
       People = new ObservableCollection<Person>(context.People.Local); 
       personViewSource.Source = People; 
      } 
     } 
    } 
} 

XAML

<Window.Resources> 
    <CollectionViewSource x:Key="personViewSource" d:DesignSource="{d:DesignInstance {x:Type local:Person}, CreateList=True}"/> 
</Window.Resources> 

<ScrollViewer> 
    <WrapPanel x:Name="PatientWrapPanel" DataContext="{StaticResource personViewSource}"> 
     <ItemsControl ItemsSource="{Binding}"> 
      <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <StackPanel> 
         <local:PersonControl/> 
        </StackPanel> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
      <ItemsControl.ItemsPanel> 
       <ItemsPanelTemplate> 
        <WrapPanel IsItemsHost="True"></WrapPanel> 
       </ItemsPanelTemplate> 
      </ItemsControl.ItemsPanel> 
     </ItemsControl> 
    </WrapPanel> 
</ScrollViewer> 

は、だから私はWrapPanelに人のコレクションを結合しています。 PersonControlにはカスタムコントロールPersonControlがあります。 XAMLで

/// <summary> 
/// Interaction logic for PersonControl.xaml 
/// </summary> 
public partial class PersonControl : UserControl 
{ 
    public PersonControl() 
    { 
     InitializeComponent(); 
    } 
} 

::人のコントロールは以下のように定義FoodChooserは、追加のカスタムユーザーコントロールである

<UserControl x:Class="WpfEntityExample.PersonControl" 
     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:WpfEntityExample" 
     mc:Ignorable="d" Background="White" Margin="5" Width="225" Height="240"> 
<Grid> 
    <Grid x:Name="grid1" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="Auto"/> 
      <ColumnDefinition Width="Auto"/> 
     </Grid.ColumnDefinitions> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="Auto"/> 
     </Grid.RowDefinitions> 
     <Label Content="Id:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="0" VerticalAlignment="Center"/> 
     <TextBox x:Name="idTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="0" Text="{Binding Id, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120"/> 
     <Label Content="Name:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="1" VerticalAlignment="Center"/> 
     <TextBox x:Name="nameTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="1" Text="{Binding Name, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120"/> 
    </Grid> 
    <local:FoodChooser DataContext="{Binding Favorites}" HorizontalAlignment="Left" Margin="10,79,0,0" VerticalAlignment="Top"/> 

</Grid> 

。 XAMLで

/// <summary> 
/// Interaction logic for FoodChooser.xaml 
/// </summary> 
public partial class FoodChooser : UserControl 
{ 
    public FoodChooser() 
    { 
     InitializeComponent(); 
    } 

    private void addButton_Click(object sender, RoutedEventArgs e) 
    { 
     //What goes here? 
    } 

    private void removeButton_Click(object sender, RoutedEventArgs e) 
    { 
     //What goes here? 
    } 

    private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 

    } 

    private void UserControl_Loaded(object sender, RoutedEventArgs e) 
    { 
     //Do not load your data at design time. 
     if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) 
     { 
      //Load your data here and assign the result to the CollectionViewSource. 
      System.Windows.Data.CollectionViewSource myCollectionViewSource = (System.Windows.Data.CollectionViewSource)this.Resources["fastFoodViewSource"]; 
      myCollectionViewSource.Source = this.DataContext; 
     } 
    } 
} 

<UserControl x:Class="WpfEntityExample.FoodChooser" 
     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:WpfEntityExample" 
     mc:Ignorable="d" 
     d:DesignHeight="160" d:DesignWidth="200" Loaded="UserControl_Loaded"> 

<UserControl.Resources> 
    <CollectionViewSource x:Key="fastFoodViewSource" d:DesignSource="{d:DesignInstance {x:Type local:FastFood}, CreateList=True}"/> 
</UserControl.Resources> 
<Grid DataContext="{StaticResource fastFoodViewSource}" Width="200" Height="160"> 
    <ListView x:Name="fastFoodListView" ItemsSource="{Binding}" Margin="0,0,10,45" SelectionMode="Single"> 
     <ListView.ItemContainerStyle> 
      <Style> 
       <Setter Property="Control.HorizontalContentAlignment" Value="Stretch"/> 
       <Setter Property="Control.VerticalContentAlignment" Value="Stretch"/> 
      </Style> 
     </ListView.ItemContainerStyle> 
     <ListView.View> 
      <GridView> 
       <GridViewColumn x:Name="nameColumn" Header="Name" Width="140"> 
        <GridViewColumn.CellTemplate> 
         <DataTemplate> 
          <ComboBox SelectedValue="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="Content" SelectionChanged="ComboBox_SelectionChanged"> 
           <ComboBoxItem>Gobias Industries</ComboBoxItem> 
           <ComboBoxItem>Banana Stand Inc.</ComboBoxItem> 
           <ComboBoxItem>Bob's Burgers</ComboBoxItem> 
          </ComboBox> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 
      </GridView> 
     </ListView.View> 
    </ListView> 
    <Button x:Name="removeButton" Content="Remove" IsEnabled="{Binding ElementName=foodBox, Path=SelectedItems.Count}" HorizontalAlignment="Left" Margin="115,130,0,0" VerticalAlignment="Top" Width="75" Click="removeButton_Click"/> 
    <Button x:Name="addButton" Content="Add" HorizontalAlignment="Left" Margin="10,130,0,0" VerticalAlignment="Top" Width="75" Click="addButton_Click"/> 
</Grid> 

私の質問は、私は人(複数可)お気に入りから新しいファーストフード項目を追加および削除する方法を私FoodChooserからでしょうか?私はコンボボックスからの更新を理解しています。これは、送信されたオブジェクトをFastFoodとしてキャストし、EFを通して再保存するという単純な問題であるためです。しかし、それらを親Personに関連させながら、どのようにFastFood項目を追加および削除し、GUIを更新することができますか? WPFのDataBindingと標準的な操作手順に欠けているものがありますか?数時間の実験から、データベース内の値を実際に更新することなく、GUIでの更新やGUIでの更新なしでデータベース内の変更を正常に実行できるようになりました。

もう一度、長い投稿と特定の問題を申し訳ありません。ソリューションが提供されるだけでなく、WPFとEntity Frameworkを組み合わせて使用​​する場合のチュートリアルに役立つリソースがあれば、さらに感謝します。私は両方を学ぼうとしていましたが、一緒に使用されている2つのリソースについては良いリソースが見つかりませんでした(基本的なMicrosoft NorthWindの例に加えて)。

答えて

0

私は、MVVMを使用することをお勧めしますので、バインディングに最適なアクションを使用して操作を処理することをお勧めします。

とにかく、コード尻であなたの現在のアプローチでは、これを使用することができます:

private void addButton_Click(object sender, RoutedEventArgs e) 
{ 
    //You cannot add here because you require two things (1) Instance of Person and (2) Data to initialize FastFood 
    //You should have the add button in your PersonControl class. 
} 

private void removeButton_Click(object sender, RoutedEventArgs e) 
{ 
    var items = fastFoodListView.SelectedItems.Select(obj => obj as FastFood); 
    var person = items[0].Person; 
    person.RemoveFavorites(items); //You then implement this in your Person class 
} 

あなたの構造は、このようなタスクのために簡単ではありません。 MVVMで同じことを行う方がはるかに簡単です。

--Edit--

あなたが "正しい" MVVMのアプローチについての詳細情報を求めたすべての権利

。私はベストを尽くすつもりですが、これが主要なトピックであることを知っています.SOには適していません。私はつもりあなたの特別な場合には

は、抽象化を使用して説明します。

次の2つのモデルがあります:PersonFastFood

のは、あなたが人のリストを表示するウィンドウを持っていると言うが、クリックであなたはモーダルを示し、そのページを含むページまたはお気に入りのページを追加または編集するための別のウィンドウ

この場合、3つのViewModelsが必要です。ビューモデルは、ビューを持つモデルを結合するもので、各ビュー(ページ、モーダルまたはコントロール)に必要です。

ビューモデルとビューをリンクする方法、アクションを作成する方法については、ウェブを検索してくださいビューモデルとアクションを使用してビュー間をナビゲートする方法について説明します。

PersonsViewModelには、人のリストがあります。人のお気に入りにナビゲートするときは、全体の人物をビューモデルに渡します。この方法で、削除するインスタンスがあり、追加すると空のファーストフードセットが作成され、現在の人物になり、空のファーストフード(または編集しないファーストフードページ)を追加/編集します。このファーストフードには、貯蓄に必要な人のインスタンスが含まれています。

申し訳ありませんもっと詳しくお答えすることはできませんでしたが、適切な経路に導くだけで十分です。

+0

あなたの最初の行について詳しく説明できますか? WPFコマンドを使用することを意味しますか? コントロールを削除し、ロジックを親Personコントロールに戻しました。何らかの理由で見つけられないという基本的な質問がもう1つあります。どのようにコードの背後にあるPersonのインスタンスにアクセスするのですか?上記のコードでは、 "person.RemoveFavorites ..."と言っています。DataContextからそのオブジェクトを取得する標準MVVM/WPFの方法は何ですか? ありがとうございます。 – Phrank

+0

Pfff。私はあなたが人を得たところを見ます。私はもっ​​と寝る必要があります.... – Phrank

+0

MVVMについての情報は編集を参照してください。 – Emad

関連する問題