我尝试将单个MenuItem的ItemsSource绑定到位于ViewModel中的ReadOnlyCollection<string>
。我已经读过ContextMenu不在主Visual树之下,所以我无法直接绑定它,但我尝试的任何方法都不起作用。我有代码片段,请让我知道我做错了什么。
<Window>
…
<DockPanel>
<!-- Task bar Icon -->
<tb:TaskbarIcon x:Name="AppNotifyIcon"
DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
ToolTipText="{Binding Source={StaticResource LocalizedStrings}, Path=Strings.MainTitle}">
<tb:TaskbarIcon.ContextMenu>
<ContextMenu DataContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="{Binding Source={StaticResource LocalizedStrings}, Path=Strings.NotifyIconOpen}" Click="MenuItem_Open_Click"/>
<MenuItem Header="Technologies" ItemsSource="{Binding to the ReadOnlyCollection of string in ViewModel}">
<MenuItem.ItemContainerStyle>
<Style>
<Setter Property="MenuItem.Command" Value="{Binding <!--Command in ViewModel-->, RelativeSource={RelativeSource AncestorType=Window}}"/>
<Setter Property="MenuItem.CommandParameter" Value="{Binding}"/> <!—Binding to the menuItem Header item -->
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
<MenuItem Header="{Binding Source={StaticResource LocalizedStrings}, Path=Strings.NotifyIconExit}" Click="MenuItem_Exit_Click"/>
</ContextMenu>
</tb:TaskbarIcon.ContextMenu>
</tb:TaskbarIcon>
…
</DockPanel>
我正在尝试绑定第二个MenuItem的ItemsSource,并且在其内部的ItemContainerStyle中我想绑定命令和commandParameter。 **更新:**我使用hardcodet的TaskbarIcon来表示wpf,如果重要的话。
由于
答案 0 :(得分:1)
尝试检查一下: 1. XAML代码:
<DataGrid x:Name="SelectDataGrid"
ItemsSource="{Binding Persons}" HorizontalAlignment="Left" CellEditEnding="SelectDataGrid_OnCellEditEnding"
VerticalAlignment="Top" AutoGenerateColumns="False" Loaded="SelectDataGrid_OnLoaded">
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Technologies" ItemsSource="{Binding MenuItems}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{Binding Command}"/>
<Setter Property="Header" Value="{Binding Content}"/>
<Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContextMenu}}, Path=DataContext}"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Command="{Binding HelloCommand}"></Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn></DataGrid>
2。上下文菜单的DataContext与datagrid和window相同。 3.在DataContext中放入下一个代码:
private void Init()
{
MenuItems = new ObservableCollection<MenuItemObject>(new List<MenuItemObject>
{
new MenuItemObject {Command = new RelayCommand<object>(Execute), Content = "A"},
new MenuItemObject {Command = new RelayCommand<object>(Execute), Content = "B"},
new MenuItemObject {Command = new RelayCommand<object>(Execute), Content = "C"},
new MenuItemObject {Command = new RelayCommand<object>(Execute), Content = "D"},
});
}
public ObservableCollection<MenuItemObject> MenuItems { get; set; }
private void Execute(object o)
{
}
4。 MenuItemsObject模型代码:
public class MenuItemObject:BaseObservableObject
{
private ICommand _command;
private string _content;
public ICommand Command
{
get { return _command; }
set
{
_command = value;
OnPropertyChanged();
}
}
public string Content
{
get { return _content; }
set
{
_content = value;
OnPropertyChanged();
}
}
}
5。 MVVM部件实现:
public class BaseObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
{
var propName = ((MemberExpression)raiser.Body).Member.Name;
OnPropertyChanged(propName);
}
protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(name);
return true;
}
return false;
}
}
public class RelayCommand<T> : ICommand
{
readonly Action<T> _execute;
readonly Func<T, bool> _canExecute;
public event EventHandler CanExecuteChanged;
public RelayCommand(Action<T> execute, Func<T, bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public void RefreshCommand()
{
var cec = CanExecuteChanged;
if (cec != null)
cec(this, EventArgs.Empty);
}
public bool CanExecute(object parameter)
{
if (_canExecute == null) return true;
return _canExecute((T)parameter);
}
public void Execute(object parameter)
{
_execute((T)parameter);
}
}
public class RelayCommand : RelayCommand<object>
{
public RelayCommand(Action execute, Func<bool> canExecute = null)
: base(_ => execute(),
_ => canExecute == null || canExecute())
{
}
}
调用Init方法生成玩具菜单项的集合DataContext。
执行是按下某个菜单项时调用的方法。
就是这样。如果代码出现问题,我很乐意提供帮助。 问候,
答案 1 :(得分:1)
好的,我已经找到了问题,这要归功于Ilan在使用snoop实用程序的评论中提出的建议。 我在可视化树中看到,ContextMenu没有将其PlacementTarget指向其父级TaskbarIcon(Weird ..),但它有一个来自TaskbarIcon的名为TaskbarIcon.ParentTaskbarIcon的附加属性,所以我绑定了ContextMenu的DataContext到TaskbarIcon.ParentTaskbarIcon.Tag并修复了所有内容。
Class clazz = (Class) Class.forName("Your class name");
for (Class c : clazz.getClass().getInterfaces()) {
String name=c.getName());
if(name.equals("org.apache.SomethingInterface"))
{
now u know u have it implemented
}
}
因此,TaskbarIcon的Tag指向Window的DataContext,ContextMenu的DataContext指向Taskbar的附加属性ParentTaskbarIcon.Tag,从现在起,每个绑定都像在可视树中的窗口一样执行。
答案 2 :(得分:0)
对于ListBox中的上下文菜单,我将我的DataContext添加到父控件的标记中,并在绑定到放置目标的相对源中找到它。关于此问题,有很多问题,其中一些可能涉及更具体的实例。
DbContext.Entry(order, ent => ent.State = EntityState.Modified;
特别是你的例子:
<ListBox ItemsSource="{Binding ItemList}"
SelectedItem="{Binding SelectedItem}"
Tag="{Binding}">
<ListBox.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Delete"
Command="{Binding Path=DeleteCommand}"/>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
当然你的绑定可能会有所不同,但是从这里开始你应该至少设置DataContext,并从那里开始。