gpt4 book ai didi

c# - 在 ItemsControl 内的 DataTemplate 内的 Button 的 WPF Databinding ContextMenu

转载 作者:行者123 更新时间:2023-12-03 10:44:15 26 4
gpt4 key购买 nike

我试图弄清楚如何绑定(bind)我拥有的 ItemsControl 中添加的 Button 的 ContextMenu。基本上,我希望能够右键单击一个按钮并将其从位于我的 View 模型上的可观察集合中删除。我知道 ContextMenu 不是 VisualTree 的一部分,因此使用 RelativeSource 向上查找我的 DataContext 对我没有用处。

我想要做的最终目标是将 MenuItem 上的命令绑定(bind)到我的 ViewModel 上的 RemoveCommand,然后传入您右键单击的 Button 的 Content 属性,以便我可以将其从可观察集合中删除。

对此的任何帮助将不胜感激。

模型:

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

View 模型:
public class SettingsWindowViewModel
{
public ObservableCollection<Preset> MyPresets { get; } = new ObservableCollection<Preset>();

private ICommand _plusCommand;
public ICommand PlusCommand => _plusCommand ?? (_plusCommand = new DelegateCommand(AddPreset));

private ICommand _removeCommand;
public ICommand RemoveCommand => _removeCommand ?? (_removeCommand = new DelegateCommand<string>(RemovePreset));

private void AddPreset()
{
var count = MyPresets.Count;
MyPresets.Add(new Preset {Name = $"Preset{count+1}"});
}

private void RemovePreset(string name)
{
var preset = MyPresets.FirstOrDefault(x => string.Equals(x.Name, name, StringComparison.CurrentCultureIgnoreCase));
if (preset!= null)
{
MyPresets.Remove(preset);
}
}
}

XAML:
<Window x:Class="WpfTesting.Esper.Views.SettingsWindow"
x:Name="MainSettingsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:WpfTesting.Esper.ViewModels"
mc:Ignorable="d"
Title="SettingsWindow" Height="470" Width="612">
<Window.DataContext>
<viewModels:SettingsWindowViewModel/>
</Window.DataContext>
<Window.Resources>
<Style BasedOn="{StaticResource {x:Type MenuItem}}" TargetType="{x:Type MenuItem}" x:Key="PopupMenuItem">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<Border>
<ContentPresenter ContentSource="Header"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="35"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<Button Width="70" Content="Load"/>
<Button Width="70" Content="Save As"/>
<ItemsControl ItemsSource="{Binding MyPresets}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Width="70" Content="{Binding Name}">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Style="{StaticResource PopupMenuItem}" Header="Remove">
<!--
I need to set up binding a Command to a method on the DataContext of the Window, and I need to pass in the Content of the Button that is the parent of the ContextMenu
-->
</MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Width="20" Background="Transparent" BorderBrush="Transparent" Content="+" FontSize="21.333" HorizontalAlignment="Center" VerticalAlignment="Center" Command="{Binding PlusCommand}"/>
</StackPanel>
</Grid>
</Window>

最佳答案

使用 WPF: Binding a ContextMenu to an MVVM Command作为对标签可以做什么的介绍,我想出了如何通过使用多个标签来保存我正在寻找的内容的上下文来做我正在寻找的东西。

我首先确保给我的窗口一个 x:Name

<Window x:Name="MainSettingsWindow"

接下来,在我的 ItemsControl 的 DataTemplate 内的按钮上,我设置了一个标签并将其设置到我的窗口
<ItemsControl ItemsSource="{Binding MyPresets}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Width="70" Content="{Binding Name}" Tag="{Binding ElementName=MainSettingsWindow}">

接下来,在 ContextMenu 中,我将 ContextMenu 的 DataContext 设置为我在 Button 上设置的 Tag,我还需要在 ContextMenu 上创建一个 Tag 并将其指向 Button 的 Content 属性,以便我可以将其传递到命令参数
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Mode=Self}}" Tag="{Binding PlacementTarget.Content, RelativeSource={RelativeSource Mode=Self}}">

此时,我现在可以使用 ViewModel 中的 Command 和 Button 中的 Content 属性正确绑定(bind) MenuItem

这是我的 ItemsControl 的最终 XAML:
<ItemsControl ItemsSource="{Binding MyPresets}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Width="70" Content="{Binding Name}" Tag="{Binding ElementName=MainSettingsWindow}">
<Button.ContextMenu>
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Mode=Self}}" Tag="{Binding PlacementTarget.Content, RelativeSource={RelativeSource Mode=Self}}">
<MenuItem Header="Remove"
Style="{StaticResource PopupMenuItem}"
Command="{Binding Path=DataContext.RemoveCommand}"
CommandParameter="{Binding Path=Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

需要注意的一点是,我必须更改 ViewModel 上的 CommandParameter 以获取对象而不是字符串。我这样做的原因是我的 DelegateCommand 中的 CanExecute 方法出现异常

这是我得到的异常(exception):
Unable to cast object of type 'MS.Internal.NamedObject' to type 'System.String'.

我不确定究竟是什么导致该异常抛出,但将其更改为 Object 对我来说可以。

关于c# - 在 ItemsControl 内的 DataTemplate 内的 Button 的 WPF Databinding ContextMenu,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35438121/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com