列表框的对象和按钮

时间:2012-02-27 21:36:25

标签: silverlight mvvm listbox mvvm-light

我是MVVM的新手。我有填充Employee列表的列表框。我正在使用MVVM light和Silverlight4

<ListBox BorderBrush="Transparent" 
         HorizontalContentAlignment="Stretch" 
         VerticalAlignment="Stretch" 
         Name="EmployeeListBox" 
         Background="Transparent" 
         ItemsSource="{Binding Employees}" 
         SelectedItem="{Binding SelectedEmployee, Mode=TwoWay}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid Margin="4">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="200"/>
                    <ColumnDefinition Width="200"/>
                    <ColumnDefinition Width="50"/>
                    <ColumnDefinition Width="50"/>
                    <ColumnDefinition Width="50"/>
                    <ColumnDefinition Width="300"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="30"/>
                    <RowDefinition Height="30"/>
                    <RowDefinition Height="30"/>
                    <RowDefinition Height="30"/>
                    <RowDefinition Height="30"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>

                <sdk:Label Grid.Row="0" Grid.Column="0"
                    Content="Name" />
                <TextBox Grid.Column="1" Grid.Row="0"
                    Name="EmployeeName" 
                    Height="23" 
                    Text="{Binding Path=Name, Mode=TwoWay}" 
                    VerticalAlignment="Center" 
                    HorizontalAlignment="Stretch" />
                <Button Grid.Column="2" Grid.Row="0"
                    Name="RefresEmployeeName"  
                    Width="20" 
                    Height="25" 
                    Command="{Binding RefreshEmployeeNameCommand}"
                    Content="Refresh" />
                <Button Grid.Column="4" Grid.Row="0" 
                    Name="DeleteEmployee"
                    Width="20" 
                    Height="25" 
                    Content="Delete" 
                    Command="{Binding DeleteEmployeeCommand}" />
                <sdk:Label Grid.Row="1" Grid.Column="0"
                    Content="Description" />
                <TextBox Grid.Column="1" Grid.Row="1" Height="23" 
                    Text="Binding Path=Description}" 
                    VerticalAlignment="Center" 
                    HorizontalAlignment="Stretch" />
                <Button Grid.Column="2" Grid.Row="1"
                    Name="RefreshDescription"  
                    Width="20" 
                    Height="25" 
                    Content="Refresh" 
                    Command="RefreshDescriptionCommand" />
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

显示文本框中显示名称和说明的员工列表,以及员工姓名和说明文本框旁边的“刷新”按钮以及“员工姓名文本”框前面的“删除”按钮。

在我的ViewModel中,我创建了3 RelayCommands作为

RelayCommand RefreshEmployeeNameCommand = new RelayCommand(RefreshEmployeeName);
RelayCommand DeleteEmployeeCommand = new RelayCommand(DeleteEmployee);
RelayCommand RefreshDescriptionCommand = new RelayCommand(RefreshDescription);

当我点击RefreshEmployeeName按钮时,如果对员工姓名进行了任何编辑,则文本框中的内容应重置为其原始值。 当我点击DeleteEmployee按钮时,应删除SelectedEmployee。 当我单击RefreshDescription按钮时,应重置对描述的任何编辑。

当我点击RefreshEmployeeName时,未在ViewModel中调用RefreshEmployeeName函数。如何捕获与此按钮关联的文本框中的数据。以及如何在单击按钮时捕获所选项目。当我点击边框附近时,所选项目会更新。

这是我的观点模型:

public IServiceAgent ServiceAgent { get; set; }

public EditViewModel(IServiceAgent serviceAgent)
{
    if (!IsDesignTime)
    {
        if (serviceAgent != null)
        {
            ServiceAgent = serviceAgent;
        }

        GetEmployees();
        WireCommands();
    }
}

private void WireCommands()
{
    RefreshEmployeeNameCommand = new RelayCommand(RefreshEmployeeName);
    DeleteEmployeeCommand = new RelayCommand(DeleteEmployee);
    RefreshEmployeeDescriptionCommand = new RelayCommand(RefreshEmployeeDescription);
}

public RelayCommand RefreshEmployeeNameCommand { get; private set; }

public RelayCommand DeleteEmployeeCommand { get; private set; }

public RelayCommand RefreshEmployeeDescriptionCommand { get; private set; }

private void RefreshEmployeeName()
{
    // have to capture the value within the textbox employee name
}

private void DeleteEmployee()
{
    // have to capture the employee object which should be deleted   
}

private void RefreshEmployeeDescription()
{
    // have to capture the value within the textbox employee description
}

private ObservableCollection<Employee> _Employees;
public ObservableCollection<Employee> Employees
{
    get
    {
        return _Employees
    }
    set
    {
        if _Employees!= value)
        {
            _Employees= value;
            OnPropertyChanged("Employees");
        }
    }
}

public Employee _SelectedEmployee;
public DisplayDevice SelectedEmployee
{
    get
    {
        return _SelectedEmployee;
    }
    set
    {
        if (_SelectedEmployee!= value)
        {
            _SelectedEmployee= value;
            OnPropertyChanged("SelectedEmployee");
        }
    }
}

private void GetEmployees()
{
    ServiceAgent.GetEmployees((s, e) => Employees = e.Result);
}

3 个答案:

答案 0 :(得分:1)

作为对出错的预感

Employees中的对象(即每一行)需要是视图模型,其中包含按钮relay命令。

您可能在主视图模型上有relay命令,但永远不会被调用,因为列表框的行绑定到Employees中的项目

答案 1 :(得分:0)

一种选择是在每个Employee对象上都有一个RelayCommand,并绑定到该对象。这样,RelayCommand执行就具有了它需要执行的所有对象上下文。

将以下内容添加到Employee对象中:

public Employee : ViewModelBase
{
    public RelayCommand RefreshDescriptionCommand {get; private set}

    // ... 

    public Employee()
    {
         RefreshDescriptionCommand = new RefreshDescriptionCommand(RefreshDescription);

    //...

    private void RefreshDescription()
    {

         //Do whatever
    }
}

您的XAML按钮需要绑定到命令。由于它们位于ItemsTemplate中,因此它们将绑定到每个Employee对象上的RefreshDescriptionCommand

<Button ...  Command="{Binding RefreshDescriptionCommand}" />

当您的命令执行时,它将在放置按钮的对象的上下文中执行,因此您可以刷新描述,更新数据,无论您需要做什么。

您需要为每个按钮重复这些步骤。

一些警告:

  1. 确保您的Employee对象实现了INotifyPropertyChanged(如果您使用的是MVVM Light,它将从ViewModelBase继承)。

  2. 不要将它放在ListBox中。对于你想要做的事情,这是一种错误的控制。 ItemsControl更适合这种情况。 ListBox在这里给你的唯一功能就是能够选择一个看起来不像你需要的项目。事实上,项目选择行为有时会滚动和按下按钮。

  3. 这可能是在SilverLight中执行此操作的最简单方法。 WPF中还有一些其他选项,绑定到祖先,但在SilverLight中更难做到。

答案 2 :(得分:0)

您的命令未被处理,因为默认情况下按钮的数据上下文是Employee实体。这是因为您将ItemsSource设置为ViewModel上的Employees属性,然后每一行都绑定到Employee实体对象。因此,Command绑定正在寻找Employee对象上的Command处理程序而不是ViewModel。

您需要在命令上设置源以指回存在命令处理程序的视图模型。这是一个例子:

Command="{Binding Source={StaticResource ViewModel}, Path=RefreshEmployeeNameCommand}" 

ViewModel ”是为视图创建的EditViewModel实例的名称。