绑定 MenuItem 的 ItemsSource 和 IsChecked 以获取 WPF 中可检查项目的列表
我正在尝试设置一个 MenuItem
,它将有一个可以选择的页码子菜单。我想将 ItemsSource
绑定到页码列表(实际上是通过创建列表的转换器绑定到 PageCount),然后绑定每个 MenuItem 的
在子菜单中添加到 PageIndex。我的问题是第二个绑定,因为它也需要转换器,但该转换器需要知道 IsChecked
属性MenuItem
表示的页码,但我无法弄清楚如何将该信息传递给转换器。这是我到目前为止所尝试过的。
<MenuItem Header="_Goto Page"
ItemsSource="{Binding
Path=CurrentImage.PageCount,
Converter={StaticResource countToList}}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="IsCheckable"
Value="True"/>
<Setter Property="IsChecked"
Value="{Binding
ElementName=MainWindow,
Path=CurrentImage.PageIndex,
Mode=TwoWay,
Converter={StaticResource pageNumChecked},
ConverterParameter={Binding
RelativeSource={RelativeSource Self},
Path=Content}}"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
当然,问题是 ConverterParameter
无法绑定,因为它不是 DependencyProperty
。所以我的问题是如何传递我需要的信息或者是否有其他方法可以做到这一点。
注意:我已经尝试将 MenuItem
放入 ListBox
中,就绑定而言效果非常好,但导致子菜单以非- 标准方式。也就是说,当您打开子菜单时,整个 ListBox
被视为一个 MenuItem
。
编辑
这就是我到目前为止所做的工作。我尝试绑定到隐藏的 ListBox
但当我将 MenuItem.ItemsSource
绑定到“ListBox.Items”时,我得到了 int
列表而不是我需要获取 IsSelected
属性的 ListBoxItem
列表。因此,我最终采用了 Quartermeister 的建议,即使用 MultiBinding 来获取 IsChecked
属性,以在 OneWay
模式下绑定到 PageIndex
。为了处理另一个方向,我在 Click
事件上使用了事件处理程序。值得注意的是,起初我将 IsCheckable
设置为 true
并使用 Checked
事件,但这导致了一些奇怪的行为。
<MenuItem x:Name="GotoPageMenuItem" Header="_Goto Page"
ItemsSource="{Binding Path=CurrentImage.PageCount,
Converter={StaticResource countToList}}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="IsCheckable"
Value="False"/>
<EventSetter Event="Click"
Handler="GotoPageMenuItem_Click"/>
<Setter Property="IsChecked">
<Setter.Value>
<MultiBinding Converter="{StaticResource pageNumChecked}"
Mode="OneWay">
<Binding RelativeSource="{RelativeSource FindAncestor,
AncestorType={x:Type Window}}"
Path="CurrentImage.PageIndex"
Mode="OneWay"/>
<Binding RelativeSource="{RelativeSource Self}"
Path="Header"
Mode="OneWay"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
这是 GotoPageMenuItem_Click
代码
private void GotoPageMenuItem_Click(object sender, RoutedEventArgs e)
{
var item = sender as MenuItem;
if (item != null)
{
//If the item is already checked then we don't need to do anything
if (!item.IsChecked)
{
var pageNum = (int)item.Header;
CurrentImage.PageIndex = (pageNum - 1);
}
}
}
I'm attempting to setup a MenuItem
that will have a submenu of page numbers that can be selected. I want to bind the ItemsSource
to a list of page numbers (actually to the PageCount with a converter creating the list) and then bind the IsChecked
property of each MenuItem
in the sub-menu to the PageIndex. My problem is with the second binding as it too requires a converter, but that converter need to know the page number that the MenuItem
represents, but I cannot figure out how to pass that information to the converter. Here's what I've tried so far.
<MenuItem Header="_Goto Page"
ItemsSource="{Binding
Path=CurrentImage.PageCount,
Converter={StaticResource countToList}}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="IsCheckable"
Value="True"/>
<Setter Property="IsChecked"
Value="{Binding
ElementName=MainWindow,
Path=CurrentImage.PageIndex,
Mode=TwoWay,
Converter={StaticResource pageNumChecked},
ConverterParameter={Binding
RelativeSource={RelativeSource Self},
Path=Content}}"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
Of course the problem is that the ConverterParameter
cannot be bound as it is not a DependencyProperty
. So my question is how can I pass in the information I need or is there another way to do this.
Note: I already tried putting the MenuItem
s inside of a ListBox
which worked really well as far as the bindings are concerned, but caused the sub-menu to behave in a non-standard way. That is when you opened the sub-menu the entire ListBox
was treated as one MenuItem
.
Edit
So here's what I've gotten to work so far. I tried binding to a hidden ListBox
but when I bound the MenuItem.ItemsSource
to the 'ListBox.Items' I got the list of int
s instead of a list of ListBoxItem
s which I needed to get the IsSelected
property. So I ended up using Quartermeister's suggestion of using MultiBinding to get the IsChecked
property to bind to the PageIndex
in OneWay
mode. To handle the other direction I used an event handler on the Click
event. It's worth noting that at first I had IsCheckable
set to true
and was working with the Checked
event, but that resulted is some odd behaviors.
<MenuItem x:Name="GotoPageMenuItem" Header="_Goto Page"
ItemsSource="{Binding Path=CurrentImage.PageCount,
Converter={StaticResource countToList}}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="IsCheckable"
Value="False"/>
<EventSetter Event="Click"
Handler="GotoPageMenuItem_Click"/>
<Setter Property="IsChecked">
<Setter.Value>
<MultiBinding Converter="{StaticResource pageNumChecked}"
Mode="OneWay">
<Binding RelativeSource="{RelativeSource FindAncestor,
AncestorType={x:Type Window}}"
Path="CurrentImage.PageIndex"
Mode="OneWay"/>
<Binding RelativeSource="{RelativeSource Self}"
Path="Header"
Mode="OneWay"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
And here's the GotoPageMenuItem_Click
code
private void GotoPageMenuItem_Click(object sender, RoutedEventArgs e)
{
var item = sender as MenuItem;
if (item != null)
{
//If the item is already checked then we don't need to do anything
if (!item.IsChecked)
{
var pageNum = (int)item.Header;
CurrentImage.PageIndex = (pageNum - 1);
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
听起来您正在尝试构建控制每个菜单项的选中状态的动态菜单。
我使用 MVVM 模式扩展了一些为在 WPF 中构建动态菜单而编写的代码,并添加了检查的逻辑。
这是 XAML:
这是视图模型:
这是保存命令的类:
Sounds like you are trying to build dynamic menus that control the checked state of each menu item.
I extended some code I wrote to build dynamic menus in WPF with the MVVM pattern and added the checked logic.
Here is the XAML:
Here is the View Model:
Here is the class that holds the commands:
您可以使用 MultiBinding?
让您的
pageNumChecked
转换器实现 IMultiValueConverter 而不是 IValueConverter,Convert 将获得一个包含每个子绑定结果的数组。在本例中,它将是一个双元素数组,其中第一个元素是当前输入 PageIndex,第二个索引是当前 ConverterParameter Content。如果您想要双向绑定,ConvertBack 将需要返回一个双元素数组,并且您将为第二个参数返回Binding.DoNothing
,以便它不会尝试更新 Content。Can you do what you want using a MultiBinding?
Have your
pageNumChecked
converter implement IMultiValueConverter instead of IValueConverter and Convert will get an array with the result of each child binding. In this case, it would be a two-element array where the first element is your current input, PageIndex, and the second index is your current ConverterParameter, Content. If you want two-way binding, ConvertBack will need to return a two-element array, and you would returnBinding.DoNothing
for the second parameter so that it does not try to update Content.