时间:2011-09-02 22:11:12

标签: c# wpf xaml data-binding binding

我有一个WPF窗口左侧有任务列表,右侧有有关所选任务的详细信息。任务只是一个任务集合,你可以认为它是POCO。

具有任务和所选任务的单个ViewModel

public class TaskViewModel
{
    public TaskViewModel()
    {
        Tasks = new Task().GetTasks();
    }


    // A LIST OF MANY TASKS
    private Tasks _tasksViewModel;
    public Tasks Tasks
    {
        get { return _tasksViewModel; }
        private set
        {
            _tasksViewModel= value;
        }
    }


    // A SINGLE SELECTED TASK
    private static readonly DependencyProperty CurrentTaskProperty = DependencyProperty.Register(
        "CurrentTask", typeof(Task), typeof(TaskViewModel), new PropertyMetadata(null));
    public Task CurrentTask
    {
        get { return (Task) GetValue(CurrentTaskProperty); }
        set { SetValue(CurrentTaskProperty, value); }
    }
}

XAML中的窗口:

<Window>
    <!-- A List with multiple tasks. -->
    <ListBox x:Name="listBoxTasks" ItemsSource="{Binding Path=Task, Mode=TwoWay} />

    <!-- The List's selected task's "Task Name" property. -->
    <TextBox x:Name="textBoxTaskName" Text="{Binding Path=CurrentTask, Mode=TwoWay}" />    

    <!-- The List's selected tasks' "Task Items" child objects. -->
    <ListBox x:Name="listBoxTaskItems" ItemsSource="{Binding Path=EditableValue, Mode=TwoWay}" />
</Window>

我的MainWindow xaml代码隐藏:

public partial class MainWindow : Window
{
    private MainWindow()
    {
        DataContext = _tasksViewModel;
    }

    private void OnListBoxTasksSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        _tasksViewModel.CurrentTask = task;
        DataContext = _tasksViewModel;
    }
}

现在的问题是:

我应该拥有多少个视图模型?

  • 我应该添加第二个ViewModel吗?我应该有一个ViewModel for Tasks和一个用于所选任务,还是我应该只有一个ViewModel用于整个窗口?

在XAML中绑定以及在C#中设置数据上下文的最佳方法是什么?

  • 如何为整个Window只有一个DataContext?如果Window的DataContext是TasksViewModel,我如何将某些东西绑定到TasksViewModel.CurrentTask?有没有办法绑定到Window.DataContext的子项的属性,还是我需要为任何使用CurrentTask的控件手动指定单独的DataContext?

    • 有没有办法像这样做:

在C#中:

DataContext = _tasksViewModel.Tasks

在XAML中:

<!-- Can I do something similar to DataContext.CurrentTask.TaskName ??? -->
<TextBox x:Name="textBoxTaskName" MinWidth="100" Text="{Binding Path=DataContext.CurrentTask.TaskName, Mode=TwoWay}" />

<!-- What about DataContext.CurrentTask.TaskItems??? -->
<ListBox x:Name="listBoxTaskItems" ItemsSource="{Binding Path=**DataContext.CurrentTask.TaskItems**, DisplayMember="TaskItemName}" />

或换句话说,有没有比这更好的解决方案:

 // When a Task in Tasks is selected...
OnListBoxTasksSelectionChanged()
{
    [...]

    // Set that Task as the DataContext for other controls
    textBoxTaskName.DataContext = Task;

    listBoxTaskItems.DataContext = Task.TaskItems;
 }

1 个答案:

答案 0 :(得分:2)

Binding中的路径可以深深地绑定到DataContext的属性中。级别用点分隔。您还可以从绑定中访问索引器。

如果您的DataContext是例如您通过说{Binding CurrentTask}绑定到CurrentTask的TasksViewModel。此外,您通常会将 ListBox SelectedItem 绑定到 CurrentTask

错误的是尝试从DependencyObject继承为ViewModel并指定依赖项属性。如果要指定绑定,则需要依赖项属性。 ViewModels只是数据源。

因此,正确的方法是通过引发属性更改的事件来实现 INotifyPropertyChanged 和notity WPF