2009-03-10 8 views
1

各リスト項目に多数のcontolsを持つリストボックスがあります。ListBoxのTextBox、Button、およびListBox

<ListBox x:Name="projectList" IsSynchronizedWithCurrentItem="True"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <StackPanel> 
       <TextBlock Text="{Binding Name}" /> 
       <ListBox x:Name="taskList" ItemsSource="{Binding Tasks}"> 
        <ListBox.ItemTemplate> 
         <DataTemplate> 
          <StackPanel> 
           <TextBlock Text="{Binding Name}" /> 
          </StackPanel> 
         </DataTemplate> 
        </ListBox.ItemTemplate> 
       </ListBox> 
       <TextBox x:Name="textBoxTask" /> 
       <Button 
        x:Name="ButtonAddNewTask" 
        Content="Test" 
        CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext}" 
        Click="ButtonAddNewTask_Click" 
        /> 
      </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

リストボックスのボタンをクリックすると、リストボックス内のリストボックスに新しいアイテムを追加します。私はこれまでに来ました。だから私の質問は、テキストボックスを保持する方法と私はどのようにリストボックスを更新するのですか?

は、ここに私のクリックイベントである

private void ButtonAddNewTask_Click(object sender, RoutedEventArgs e) 
{ 
    Button button = (Button)sender; 
    Project proj = button.DataContext as Project; 
    if(proj.Tasks == null) 
     proj.Tasks = new List<Task>(); 

    proj.Tasks.Add(new Task("Added Task")); 
} 

ありがとう

+0

「テキストボックスを取得する」と正確にはどういう意味ですか? – Joey

+0

目的は、テキストボックスのテキストを使用してタスクを作成することでした。 TextBox newTaskTextBox =ここにはありません。 proj.Tasks.Add(新しいタスク(newTaskTextBox.Text)); –

答えて

0

この解決策は、話す側の仕事のために働いていました。

private void ButtonAddNewTask_Click(object sender, RoutedEventArgs e) 
    { 
     Button button = (Button)sender; 
     DependencyObject obj = LogicalTreeHelper.GetParent(button); 
     StackPanel item = obj as StackPanel; 
     TextBox textBox = item.FindName("textBoxTask") as TextBox; 
     ListBox listBox = item.FindName("taskList") as ListBox; 

     Project proj = button.DataContext as Project; 
     if(proj.Tasks == null) 
      proj.Tasks = new List<Task>(); 

     listBox.ItemsSource = proj.Tasks; 
     listBox.Items.Refresh(); 
    } 
+0

それは動作しますが、それは最高のソリューションIMOではありません。コントロールからデータを引き出すのではなく、モデルオブジェクトとやり取りする方がはるかに優れています。 – Andy

+0

今日私のために記述されたModelViewが得られました。私はwebbformsの開発者であり、私はちょっと違うと思うのです。私はあなたの例を試しています。 –

7

最も簡単な解決策は、おそらく1つの目的は、外側のリストボックス内の各項目を表す持っているだろう。次に、アイテム内の各コントロール、つまりTextBoxのテキスト、ListBoxのアイテム(Clickハンドラに基づいたタスクのリスト)を表すプロパティを持ちます。

Clickハンドラでは、ButtonのDataContext(外部リストのコレクション内の項目である必要があります)を取得し、そのオブジェクトのタスクリストに新しいTaskを追加できます。内側のListBoxはそのリストにバインドされているため、新しい項目で更新する必要があります(ObservableCollectionなどのアイテムが追加されたときにイベントを送信すると仮定して)。

更新:あなたのコメントに基づいて、以下が動作するはずです。 - タスクの名前を

class Project 
{ 
    public string Name { get; set; } 

    private ObservableCollection<Task> tasks = 
     new ObservableCollection<Task>(); 
    public IList<Task> Tasks 
    { 
     get { return this.tasks; } 
    } 
} 

Taskクラスだけつのプロパティを持っています

あなたProjectクラスには、二つの特性を持っている必要があります。

ProjectViewクラスは、Projectクラスのラッパーです(このアイデアは@thothymcgrathの回答から得ました)。これは、新しいタスクの名前を追跡し、現在Project

class ProjectView : INotifyPropertyChanged 
{ 
    public Project Project { get; set; } 

    private string newTaskName = string.Empty; 
    public string NewTaskName 
    { 
     get { return this.newTaskName; } 
     set 
     { 
      this.newTaskName = value; 
      this.OnPropertyChanged("NewTaskName"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propName) 
    { 
     PropertyChangedEventHandler eh = this.PropertyChanged; 
     if(null != eh) 
     { 
      eh(this, new PropertyChangedEventArgs(propName)); 
     } 
    } 
} 

あなたはDataContextとして使用される新しいクラスが必要になります。このような何か:コードビハインドで

class Model 
{ 
    private ObservableCollection<ProjectView> projects = 
     new ObservableCollection<ProjectView>(); 
    public IList<ProjectView> Projects 
    { 
     get { return this.projects; } 
    } 
} 

、上記クラスのインスタンスへのオブジェクトのDataContextを設定:XAMLで

public class Window1 
{ 
    public Window1() 
    { 
     this.InitializeComponent(); 

     this.DataContext = this.model; 
    } 

    private Model model = new Model(); 
} 

、バインディングはに結合するように改変されなければなりません上記のプロパティ:

<ListBox x:Name="projectList" IsSynchronizedWithCurrentItem="True" 
    ItemsSource="{Binding Path=Projects}"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <StackPanel> 
       <TextBlock Text="{Binding Project.Name}" /> 
       <ListBox x:Name="taskList" 
        ItemsSource="{Binding Project.Tasks}" 
        DisplayMemberPath="Name" /> 
       <TextBox x:Name="textBoxTask" 
        Text="{Binding Path=NewTaskName, UpdateSourceTrigger=PropertyChanged}"/> 
       <Button x:Name="ButtonAddNewTask" Content="Test" 
        Click="ButtonAddNewTask_Click" /> 
      </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

最後に、ボタンのクリックハンドラで、タスクを作成します。 ButtonDataContextは、その項目のProjectViewになります。

private void ButtonAddNewTask_Click(object sender, RoutedEventArgs e) 
{ 
    Button btn = (Button)sender; 
    ProjectView curProject = btn.DataContext as Project; 
    if(null != curProject) 
    { 
     curProject.Project.Tasks.Add(new Task() 
     { 
      Name = curProject.NewTaskName 
     }); 
    } 
} 

すべてのコントロールが結合することにより、それらの値を取得するので、あなたは、データを取得するには、コントロール自体にアクセスする必要はありません - ちょうど、すでにコントロールを供給しているデータ構造を使用します。

タスクを作成するコードを別のクラス(おそらくProject)に移動する方が良いでしょうが、私は自分のパーツで簡単に入力できるようにイベントハンドラに残しました。

アップデート2:UIで使用するためProjectのインスタンスをラップ別のクラスにNewTaskNameプロパティを移動するために上記のコードを変更されました。これはあなたのためにうまくいくのですか?

+0

ここに問題があるのは、私がdatacontextを取得しても、この場合のプロジェクトでは、Add new taskテキストボックスを取得できないので、プロジェクトにタスクを追加すると、タスク名の値を取得できません。テキストボックス。 –

+0

しかし、TextBoxは必要ありません。代わりに、DataContextには、TextBox.Textがバインドされているプロジェクトの名前が含まれている必要があります。 – Andy

+0

しかし、ボタンを押したときに新しいタスクを作成するにはどうすればいいですか?私はテキストボックスの中に何があるかを知る必要があります。 –

2

私はあなたのプロジェクトリストボックスがプロジェクトオブジェクトのコレクションで設定されていると仮定しています。 AddNewTask ICommandをProjectクラスに追加し、プロパティを介して公開します。次にAdd New Taskボタンを新しいAddNewTask ICommandにバインドします。 CommandParameterの場合、TaskNameを入力すると、コマンドに渡されます。

MVVM(Model View ViewModel)のいくつかの例を読んでみてください。とても清潔で素晴らしい作品です。

+0

Model ViewModelのコンセプトについて詳しく説明します。しかし、UIに関するコードでオブジェクトを乱雑にすることは、私にとって本当に悪いコンセプトのように感じます。だから私はできるだけこれを避けたい。 –

+1

したがって、実際に行うべきことは、実際のビジネスオブジェクトをViewModelオブジェクトでラップすることです。これは基本的にProjectオブジェクトをラップするオブジェクトですが、WPF UIで動作するようにProjectオブジェクトを変換します。次に、コマンドをProject ViewModelオブジェクトに配置します。 – timothymcgrath