C# MVVM-带参数的行为或查找特定的父/用户控制资源
所以,我对MVVM还相当陌生,我已经回到了一个有趣的角落,我不知道如何使用行为或命令使事情正常工作。我有一个用户控件,其中包含一个项目列表框,需要实现各种行为,例如删除或删除给定项目。像这样:C# MVVM-带参数的行为或查找特定的父/用户控制资源,c#,wpf,mvvm,C#,Wpf,Mvvm,所以,我对MVVM还相当陌生,我已经回到了一个有趣的角落,我不知道如何使用行为或命令使事情正常工作。我有一个用户控件,其中包含一个项目列表框,需要实现各种行为,例如删除或删除给定项目。像这样: <UserControl> // DataContext is a viewmodel // Borders, grids, various nesting controls... <ListBox x:Name="ListBox_Items" ItemSource="{
<UserControl> // DataContext is a viewmodel
// Borders, grids, various nesting controls...
<ListBox x:Name="ListBox_Items" ItemSource="{Binding ItemsList}">
<ListBox.ItemTemplate>
<DataTemplate> // From here on the individual item has its own data context of type Item in ItemsList
<StackPanel Orientation="Horizontal">
<TextBox Name="EditItemStuffOnLoseFocus" Text="{Binding ItemStuff}"/>
<Button Name="DeleteItemStuff"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>
当然,这个消息框并不是以应用程序为中心的,虽然小,但很烦人。一位同事建议我用一个行为替换命令,这样我就可以有一个关联的对象用于将消息框居中。问题是,我无法找到有关将参数传递给行为的任何信息,也无法找到如何将多个级别从关联对象追溯到其父对象的信息,以便获得重载步骤的视图模型以及单个项的模型(关联对象的DataContext)
总之,有没有一种方法可以在保持MVVM友好的同时将MessageBox集中在命令中的应用程序上,或者使用行为传递参数/检索特定的父对象或其资源
____________更新____________
下面的答案很好,但我采用了另一种方法,以便在MessageBox中使用DataContext变量。通过将视图模型添加到控件的标记中,我成功地保留了对调用控件和视图模型的DataContext的访问:
<UserControl> // DataContext is a viewmodel
// Borders, grids, various nesting controls...
<ListBox x:Name="ListBox_Items" ItemSource="{Binding ItemsList}">
<ListBox.ItemTemplate>
<DataTemplate> // From here on the individual item has its own data context of type Item in ItemsList
<StackPanel Orientation="Horizontal">
<TextBox Name="EditItemStuffOnLoseFocus" Text="{Binding ItemStuff}" Tag={Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=DataContext}"/>
<Button Name="DeleteItemStuff" Tag={Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=DataContext}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>
谢谢大家的帮助。要在窗口上居中显示消息框,您需要实现自己的窗口,并执行一个可指定位置的显示对话框。或者,您可以从中完成的Forms控件继承 然而,对于问题的第一部分,在按钮上实现一个click处理程序并将delete作为依赖属性绑定到用户控件可能会更容易。这将允许您访问发送方并将UI完全保留在控件内 xaml
只需从外部绑定delete命令,并在click事件中为消息框执行逻辑 要在窗口上居中显示消息框,您需要实现自己的窗口,并执行ShowDialog,您可以在其中指定位置。或者,您可以从中完成的Forms控件继承 然而,对于问题的第一部分,在按钮上实现一个click处理程序并将delete作为依赖属性绑定到用户控件可能会更容易。这将允许您访问发送方并将UI完全保留在控件内 xaml
只需从外部绑定delete命令,并在click事件中为消息框执行逻辑 谢谢你的回复!我看到了解决方案如何使用FrameworkElement在不破坏MVVM的情况下传递按钮的DataContext,但我仍然希望它不依赖于背后的代码(主要是因为我真的希望在消息框消息中显示一些DataContext信息,而不会使代码与所使用的模型有太多的关联)。我将再等一段时间,然后查看代码项目解决方案。我认为您是正确的,但是范例是,视图确实知道有关viewmodel的一些信息。这就是为什么我们静态地声明绑定。如果您希望使信息尽可能松散耦合,我建议让viewmodel从nd接口,该接口将以字符串形式提供数据。另一种选择是,您可以拥有一个附加属性,该属性绑定到您希望传递的字符串,然后您可以在代码隐藏中获取该附加属性。我不确定您是否要摆脱代码隐藏。最终,您将转到另一个路径以保留viewModel access,但我要将此标记为答案,因为它适用于发布的问题。我还将更新我的问题,以提供我使用的解决方法,以防它对其他人有帮助。感谢您的回答!我看到了解决方案如何使用FrameworkElement传递按钮的数据上下文而不破坏MVVM,但我仍然希望它能够不依赖代码隐藏(主要是因为我确实希望在消息框消息中显示一些DataContext信息,而不会使代码隐藏与所使用的模型有太多的联系)。我将再等一段时间,然后查看代码项目解决方案。我认为您是正确的,但是范例是,视图确实知道有关viewmodel的一些信息。这就是为什么我们静态地声明绑定。如果您希望使信息尽可能松散耦合,我建议让viewmodel从nd接口,该接口将以字符串形式提供数据。另一种选择是,您可以拥有一个附加属性,该属性绑定到您希望传递的字符串,然后您可以在代码隐藏中获取该附加属性。我不确定您是否要摆脱代码隐藏。最终,您将转到另一个路径以保留viewModel access,但我要将此标记为答案,因为它适用于发布的问题。我还将更新我的问题,以提供我使用的解决方法,以防它对其他人有帮助。我不确定这对您的解决方案来说是否过份,但我一直在WPF应用程序中对任何类型的弹出窗口使用自定义UserControl。如果你有兴趣尝试这种方法,或者我可以把它写下来作为一个完整的答案,并详细说明它是如何实现的。我不确定这对你的解决方案来说是否太过分了,但我一直在我的WPF应用程序中对任何类型的弹出窗口使用自定义用户控件。如果你有兴趣尝试这种方法,我会发布我使用的代码,或者我可以把它写下来作为一个完整的答案,更详细地说明它是如何实现的。
<UserControl> // DataContext is a viewmodel
// Borders, grids, various nesting controls...
<ListBox x:Name="ListBox_Items" ItemSource="{Binding ItemsList}">
<ListBox.ItemTemplate>
<DataTemplate> // From here on the individual item has its own data context of type Item in ItemsList
<StackPanel Orientation="Horizontal">
<TextBox Name="EditItemStuffOnLoseFocus" Text="{Binding ItemStuff}" Tag={Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=DataContext}"/>
<Button Name="DeleteItemStuff" Tag={Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=DataContext}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>
ExampleViewModel viewModel = (ExampleViewModel)AssociatedObject.Tag;
Item parameter = (Item)AssociatedObject.DataContext;
if (MessageBox.Show(Window.GetWindow(AssociatedObject), "Really delete the item?", "Delete Item", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
{
ItemService service = new ItemService();
service.RemoveItem(((Item)parameter).ItemID);
if (viewModel.ReloadItemListCommand.CanExecute(viewModel.ItemInfo))
viewModel.ReloadItemListCommand(viewModel.ItemInfo);
}
}
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label Content="{Binding Name}" />
<Button Click="Button_Click" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
public ICommand DeleteItem
{
get { return (ICommand)GetValue(DeleteItemProperty); }
set { SetValue(DeleteItemProperty, value); }
}
public static readonly DependencyProperty DeleteItemProperty = DependencyProperty.Register("DeleteItem", typeof(ICommand), typeof(control), new PropertyMetadata(null));
private void Button_Click(object sender, RoutedEventArgs e)
{
if (DeleteItem != null)
{
var result = System.Windows.MessageBox.Show("WOULD YOU LIKE TO DELETE?", "Delete", MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result == MessageBoxResult.Yes)
{
var fe = sender as FrameworkElement;
if (DeleteItem.CanExecute(fe.DataContext))
{
DeleteItem.Execute(fe.DataContext);
}
}
}