C# 将关联菜单绑定到视图模型属性
我有一个关联菜单,它绑定到datagrid中的一个按钮。我希望上下文菜单项根据视图模型中的字符串列表进行更改。当我点击按钮时,什么也没有显示 下面是我正在使用的xaml,它位于datagrid中:C# 将关联菜单绑定到视图模型属性,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,我有一个关联菜单,它绑定到datagrid中的一个按钮。我希望上下文菜单项根据视图模型中的字符串列表进行更改。当我点击按钮时,什么也没有显示 下面是我正在使用的xaml,它位于datagrid中: <Button Grid.Column="1" Content="..." Click="Button_Click"> <Button.ContextMenu> <ContextMenu ItemsSource="{Binding Rela
<Button Grid.Column="1" Content="..." Click="Button_Click">
<Button.ContextMenu>
<ContextMenu ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Path=DataContext.SelectableDescriptions}">
<TextBlock Text="{Binding}"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
以下是整个DataGrid xaml:
<DataGrid Grid.Row="1" Grid.ColumnSpan="4" CanUserAddRows="True" AutoGenerateColumns="False" CanUserDeleteRows="True" ItemsSource="{Binding JobPricings, Mode=TwoWay}" SelectedItem="{Binding SelectedJobPricing, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<DataGrid.Columns>
<DataGridTemplateColumn Header="Description" Width="25*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75*"/>
<ColumnDefinition Width="25*"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding Description,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Button Grid.Column="1" Content="..." Click="Button_Click">
<Button.ContextMenu>
<ContextMenu ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Path=DataContext.SelectableDescriptions}">
<TextBlock Text="{Binding}"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Unit Price" Binding="{Binding UnitPrice, Mode=TwoWay}" Width="25*"/>
<DataGridTextColumn Header="Unit" Binding="{Binding Unit, Mode=TwoWay}" Width="25*"/>
<DataGridTemplateColumn Header="Currency " Width="25*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<ComboBox SelectedValue="{Binding CurrencyID, Mode=TwoWay}" SelectedValuePath="ID" DisplayMemberPath="Description" ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Path=DataContext.Currencies}" ></ComboBox>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
以下是通过视图模型将关联菜单绑定到的属性:
public ObservableCollection<string> SelectableDescriptions
{
get
{
_selectableDescriptions.Add("One");
_selectableDescriptions.Add("Two");
return _selectableDescriptions;
}
set
{
_selectableDescriptions = value;
}
}
public observeablecollection SelectableDescriptions
{
得到
{
_可选择的描述。添加(“一”);
_可选择的描述。添加(“两个”);
返回_selectabledescription;
}
设置
{
_selectableDescriptions=值;
}
}
你知道为什么我的列表不会出现在关联菜单中吗 我认为您必须对您的上下文菜单执行类似的操作,请注意,我的假设是您设置货币的方式正在运行
<ContextMenu>
<ContextMenu.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
上下文菜单和弹出窗口等内容存在于主视觉树之外,因此无法使用RelativeSource向上移动到父对象。在大多数情况下,ElementName也会中断。根据具体情况,有各种解决办法。我喜欢使用继承的附加属性来传递额外的数据,因为它不涉及更改您的VM,并且在您设置好它之后就保留在XAML中。这里有一篇博客文章用例子解释了这项技术:正如John所说,上下文菜单是它自己的独立窗口,与按钮的视觉树分离,因此它不会自动继承按钮的数据上下文
但是,ContextMenu确实有一个指向它所放置对象的链接(本例中的按钮):PlacementTarget
。通过转到菜单的PlacementTarget可以找到按钮,找到按钮后可以找到其DataContext
因此,在xaml中,您可以通过将自己的DataContext绑定到自己的PlacementTarget.DataContext
,手动使ContextMenu继承按钮的DataContext,并且所有其他绑定(例如,对于ItemsSource
)都可以像平常一样编写:
<Button Grid.Column="1" Content="..." Click="Button_Click">
<Button.ContextMenu>
<ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.DataContext}"
ItemsSource="{Binding Path=SelectableDescriptions}" >
<ContextMenu.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=SomePropertyOnItem}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</Button.ContextMenu>
</Button>
我最终在代码隐藏中为ContextMenu设置了ItemsSource(尽管我真的不想使用这种方法:),这很有效
这是xaml
<Button Grid.Column="1" Content="..." Name="ellipseButton" Click="ellipseButton_Click">
<Button.ContextMenu>
<ContextMenu >
<ContextMenu.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</Button.ContextMenu>
</Button>
您是否实现了INotifyPropertyChanged
?以前实现过,但它不起作用。无论如何,如果我没有弄错的话,您不应该使用ObservableCollectionDataContext=JobPricingViewModel。。。这里没有显示。我在后面的代码中设置了它。当你说“无显示”时,你的意思是没有项目,还是有许多空项目?菜单中没有显示项目。我可以看到SelectableDescriptions中有一些项目,但我需要检查一下。我读了一遍,但还是弄糊涂了。英雄联盟我会再看一遍,虽然这可能是有希望的,但当我尝试它时,我会在上下文菜单中显示数据类型。在这种情况下,这可能没有帮助,因为菜单位于项上,所以按钮DataContext是该项数据,而不是所需的主UC DataContext。@DJBurb-抱歉,代码错误。TextBlock
需要进入DataTemplate
中来描述每个菜单项的外观。我已经更新了我的答案。它之前所做的是将TextBlock用作唯一的菜单项,覆盖ItemsSource绑定。注意:您在文本块上看到的数据类型必须是保存SelectableDescriptions
列表的数据类型。如果不是,则@John的评论是正确的。SelectableDescriptions是一个字符串列表,因此我不确定@DJBurb的绑定中应该包含什么-在这种情况下,您只需使用一个没有路径的绑定(就像最初一样):…
private void ellipseButton_Click(object sender, RoutedEventArgs e)
{
var button = sender as Button;
button.ContextMenu.ItemsSource = JobPricingViewModel.SelectableDescriptions;
if (button != null) button.ContextMenu.IsEnabled = true;
var placementTarget = sender as Button;
if (placementTarget != null) placementTarget.ContextMenu.PlacementTarget = placementTarget;
var button1 = sender as Button;
if (button1 != null)
button1.ContextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
var button2 = sender as Button;
if (button2 != null) button2.ContextMenu.IsOpen = true;
}