我是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);
}
答案 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}" />
当您的命令执行时,它将在放置按钮的对象的上下文中执行,因此您可以刷新描述,更新数据,无论您需要做什么。
您需要为每个按钮重复这些步骤。
一些警告:
确保您的Employee对象实现了INotifyPropertyChanged(如果您使用的是MVVM Light,它将从ViewModelBase继承)。
不要将它放在ListBox中。对于你想要做的事情,这是一种错误的控制。 ItemsControl更适合这种情况。 ListBox在这里给你的唯一功能就是能够选择一个看起来不像你需要的项目。事实上,项目选择行为有时会滚动和按下按钮。
这可能是在SilverLight中执行此操作的最简单方法。 WPF中还有一些其他选项,绑定到祖先,但在SilverLight中更难做到。
答案 2 :(得分:0)
您的命令未被处理,因为默认情况下按钮的数据上下文是Employee实体。这是因为您将ItemsSource设置为ViewModel上的Employees属性,然后每一行都绑定到Employee实体对象。因此,Command绑定正在寻找Employee对象上的Command处理程序而不是ViewModel。
您需要在命令上设置源以指回存在命令处理程序的视图模型。这是一个例子:
Command="{Binding Source={StaticResource ViewModel}, Path=RefreshEmployeeNameCommand}"
“ ViewModel ”是为视图创建的EditViewModel实例的名称。