2009-03-10 3 views
1

각 목록 항목에 일련의 contols가있는 목록 상자가 있습니다.TextBox, Button 및 ListBox의 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

그게 효과가 있지만, 그것은 최고의 해결책이 아닙니다. 컨트롤에서 데이터를 가져 오는 것보다는 모델 개체와 상호 작용하는 것이 훨씬 낫습니다. – Andy

+0

오늘 ModelView를 설명해주었습니다. 나는 webbforms 개발자이고, 내가 왜 조금 다른 것 같아. 나는 너의 모범을 보여주고있다. –

7

가장 쉬운 해결책은 가능성이 하나의 객체가 외부 목록 상자의 각 항목을 표현해야하는 것입니다. 그런 다음 항목의 각 컨트롤 (TextBox의 텍스트)과 ListBox의 항목 (클릭 핸들러를 기반으로하는 작업 목록)을 나타내는 속성을 갖게됩니다.

클릭 핸들러에서 Button의 DataContext (바깥 쪽 목록 컬렉션의 항목이어야 함)를 가져와 새 할 일을 해당 할 일 목록에 추가 할 수 있습니다. 내부 목록 상자는 해당 목록에 바인딩되므로 새 항목으로 업데이트해야합니다 (항목이 추가 될 때 ObservableCollection과 같은 이벤트를 전송한다고 가정).

업데이트 : 귀하의 의견에 따라 다음이 작동합니다.

귀하의 Project 클래스는 두 가지 속성이 있어야합니다

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

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

Task 클래스는 단지 하나 개의 속성이 있습니다 - 작업의 이름입니다.

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을 설정

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

     this.DataContext = this.model; 
    } 

    private Model model = new Model(); 
} 

XAML에서, 바인딩은 바인딩을 수정해야 위의 속성 :

마지막으로 단추의 클릭 핸들러에서 작업을 만듭니다. 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 
     }); 
    } 
} 

바인딩을 통해 그 값을 얻을, 당신은 데이터를 얻을 수있는 컨트롤 자체에 액세스 할 필요가 없습니다 - 그냥 이미 컨트롤을 제공하는 데이터 구조를 사용합니다.

아마도 Task를 만드는 코드를 다른 클래스 (아마도 Project)로 옮기는 것이 더 나을 것입니다. 그러나 저는 그냥 내 부분에 쉽게 타이핑 할 수 있도록 이벤트 처리기에 남겨 두었습니다.

업데이트 2 : 사용자 인터페이스와 함께 사용 Project의 인스턴스를 감싸고 분리 클래스로 NewTaskName 속성 이동 위의 코드를 수정. 이 방법이 효과가 있습니까?

+0

문제는 여기 datacontext 얻을 경우,이 경우에는 프로젝트를 추가 할 수 없습니다. 새 작업 추가 텍스트 상자 그래서 나는 프로젝트에서 작업 이름에 대한 값을 얻을 수없는 작업을 추가 할 수 없습니다. 텍스트 상자. –

+0

그래도 TextBox가 필요 없습니다. 대신 DataContext에는 TextBox.Text가 바인딩되는 Project의 이름이 포함되어야합니다. – Andy

+0

그렇다면 버튼을 누를 때 어떻게 새 작업을 만들 수 있습니까? 나는 텍스트 박스 안에 뭐가 있는지 알아야 해. –

2

프로젝트 목록 상자에 프로젝트 개체 모음이 채워져 있다고 가정합니다. AddNewTask ICommand를 Project 클래스에 추가하고 속성을 통해 노출합니다. 그런 다음 Add New Task 단추를 새 AddNewTask ICommand에 바인딩하십시오. CommandParameter의 경우 TaskName을 입력하면 명령에 전달됩니다.

일부 MVVM (Model View ViewModel)에서이 기능의 작동 예에 대해 읽어보십시오. 그것은 매우 깨끗하고 훌륭한 작품입니다.

+0

Model ViewModel 개념에 대해 더 자세히 읽어 보겠습니다. 하지만 UI에 관한 코드로 upp 객체를 복잡하게 만드는 것은 나에게 정말 나쁜 개념이라고 느낍니다. 그래서 나는 이것을 가능한 한 많이 피하고 싶습니다. –

+1

그럼, 실제로해야 할 일은 실제 비즈니스 객체를 ViewModel 객체로 포장하는 것입니다. 기본적으로 Project 개체를 래핑하는 개체이지만 Project 개체를 WPF UI로 작업 할 수 있도록 변환합니다. 그런 다음 Command를 Project ViewModel 객체에 놓습니다. – timothymcgrath

관련 문제