【问题标题】:WPF Menuitem inside ItemsControlItemsControl 中的 WPF Menuitem
【发布时间】:2016-02-09 07:31:41
【问题描述】:

我正在尝试做一个最近的上传系统,所以我在 contextMenu 中列出了最近 5 个(或更少)的上传。

问题是当我在做静态测试版本(非动态)时,一切都很好。喜欢可以显示这个截图:

现在有了我的动态版本:

<ItemsControl ItemsSource="{Binding Uploads}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel></StackPanel>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <MenuItem IsCheckable="False" ItemsSource="{Binding}">
                    <MenuItem.Icon>
                        <Image Source="Resources/upload.ico"></Image>
                    </MenuItem.Icon>
                    <MenuItem.Header>
                        <TextBlock Text="{Binding name}"></TextBlock>
                    </MenuItem.Header>
                    <DataTemplate>
                        <StackPanel>
                            <MenuItem Command="{Binding GoToUrl}" CommandParameter="{Binding url}">
                                <MenuItem.Header>
                                    <Image IsEnabled="False" HorizontalAlignment="Center" Source="{Binding miniature}"></Image>
                                </MenuItem.Header>
                            </MenuItem>
                            <Separator/>
                            <MenuItem IsEnabled="False" IsCheckable="False">
                                <MenuItem.Header>
                                    <StackPanel IsEnabled="False">
                                        <TextBlock IsEnabled="False" Text="{Binding uploadDateText}"></TextBlock>
                                        <TextBlock IsEnabled="False"  Text="{Binding viewNumberText}"></TextBlock>
                                    </StackPanel>
                                </MenuItem.Header>
                            </MenuItem>
                            <Separator/>
                            <MenuItem Header="Copy To Clipboard" Command="{Binding CopyToClip}" CommandParameter="{Binding url}" />
                            <MenuItem Header="Open in browser" Command="{Binding GoToUrl}" CommandParameter="{Binding url}" />
                            <MenuItem Header="Delete" Command="{Binding Delete}" CommandParameter="{Binding}" />
                        </StackPanel>
                    </DataTemplate>
                </MenuItem>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

问题是,当您在另一个 menuItem 中有一个 menuItem 时,会有一个小箭头,但是由于我已经用 ItemsControl 包装了所有内容,所以我无法访问 submenuItem,并且出现了一个奇怪的选择错误。

我在this question 中看到了有关为什么它没有按预期工作的信息。由于itemsControl 就像一个menuItem。但我没有找到另一种方法。

我的目标是 MenuItem 的“foreach 循环”,其中包含其他 menuItem。也许我没有好的方法。

P.S:对不起,我的英语不好,我是法国人。

编辑1:

看来我还不够清楚,所以我补充了一些信息。

目标:客户每次上传最多有 5 个菜单。如果他只做了 3,那么 3 Menu 将在上下文菜单中。 Foreach 菜单的标题将是他上传的文件的名称。 如果用户想了解更多关于上传的信息,他会将鼠标悬停在上传名称上,然后会绘制一个子菜单。 此子菜单将显示有关上传的所有信息:图片、大小、上传日期等...

我是如何做到的:我创建了一个类,该类将从 Web API 接收所有需要的信息:上传

public class Upload
{
    public string uniqueId { get; set; }
    public DateTime uploadedDateTime { get; set; }
    public int _viewNumber { get; set; }
    public string url { get; set; }
    public string minUrl { get; set; }
    public string type { get; set; }
    public int size { get; set; }
    public string name { get; set; }

    public BitmapImage miniature
    {
        get
        {
            BitmapImage bitmap = new BitmapImage();
            bitmap.BeginInit();
            bitmap.UriSource = new Uri(this.minUrl, UriKind.Absolute);
            bitmap.EndInit();

            return bitmap;
        }
    }

    public string uploadDateText
    {
        get
        {
            return "Uploaded : " + this.uploadedDateTime.Date.ToString() + " at " + this.uploadedDateTime.TimeOfDay.ToString();
        }
    }

    public string viewNumberText
    {
        get
        {
            return "Number of views : " + this._viewNumber;
        }
    }

    public Upload(string p_uniqueId, DateTime p_uploadedDateTime, int p_viewNumber, string p_url, string p_minUrl, string p_type, int p_size, string p_name)
    {
        uniqueId = p_uniqueId;
        uploadedDateTime = p_uploadedDateTime;
        _viewNumber = p_viewNumber;
        url = p_url;
        minUrl = p_minUrl;
        type = p_type;
        size = p_size;
        name = p_name;
    }

    public void delete()
    {
        MessageBox.Show("Deleting item with id : " + this.uniqueId);
    }

    public void refresh()
    {

    }
}

所以当我向我的 WebApp 询问我的用户的最后 5 次上传时,我会有一个列表。

最多包含 5 个项目

为了使该列表可用于我的 contextMenu,我使用以下代码将其转换为 ObservableCollection:

public ObservableCollection<Upload> Uploads
    {
        get
        {
            App.GetAppRef().initUploads();
            return App.GetAppRef().Uploads;
        }

    }

我花了很多时间来寻找一种在我的上下文菜单中拥有可变数量的 menuItem 的方法。如果用户只上传了 2 个文件,确实可以有 2 个 menuItem。这是一种 FIFO 队列样式(先进先出),最多 5 个元素。

所以我看一下 xaml 中的“foreach”等价物。但我只找到了一种使用 ItemsControl 执行“xaml foreach”的方法,他的 itemSource 绑定到我的 ObservableCollection 上传。

如果有人对此有更好的想法,请告诉我,因为我知道这可能不是最好的解决方案。

无论如何,我在上下文菜单中的“最后 5 次上传”部分之前和之后还有其他 menuItem,因此我必须在上下文菜单的特定区域内进行 foreach。

问题是什么:目前,我无法继续使用 subitemMenu,并且我的 itemControls 已启用选择,因此我需要找到更好的方法来实现这一点。

我希望我已经澄清了我的问题。

【问题讨论】:

  • 不确定我是否理解您想要实现的目标。动态是指您想要定义一个可以作为子菜单添加到其他菜单项的某个菜单模板吗?
  • 好吧,我的 webApi 会给我用户上传的最后一张图片,我希望我的用户能够获得他们在桌面客户端上传的最后 5 张图片。所以我有一个由 5 个对象组成的数组,我需要一个带有他名字的菜单项,如果你把光标放在它上面,它会显示更多细节,就像我发布的屏幕截图一样。
  • 我想我明白你的意思了。这个问题似乎涉及您需要的菜单中的动态/静态组合:stackoverflow.com/questions/14489112/…。至于为每个动态菜单项添加子菜单,请尝试将其添加到该问题给出的答案的 部分。
  • 谢谢看看这个
  • 如果没有可靠地重现问题的良好minimal reproducible example,任何人都无法尝试解决您的特定问题。但是请注意,MenuItem 已经一个ItemsControl;目前尚不清楚为什么要将菜单“包装”在一个裸露的 ItemsControl 元素中。如果您改进了问题,请务必说明您这样做的原因,而不是直接使用 MenuItem

标签: c# wpf


【解决方案1】:

好的,我花了一些时间才找到它,但这是一个有效的答案(我将它从 stackoverflow 上找到的几个答案结合起来)。
Xaml:

<local:MyStyleSelector x:Key="MyStyleSelector" />

<Style x:Key="DynamicItemStyle" TargetType="MenuItem">
    <Setter Property="Header" Value="{Binding Path=Title}"/>
    <Setter Property="ItemsSource">
        <Setter.Value>
            <x:Array Type="FrameworkElement">
                <MenuItem Header="Active" IsCheckable="True" IsChecked="{Binding Path=Active}"></MenuItem>
                <Separator></Separator>
                <MenuItem Header="Edit" Name="EditCustomMessageButton" Style="{x:Null}"></MenuItem>
                <MenuItem Header="Delete" Name="DeleteCustomMessageButton" Style="{x:Null}"></MenuItem>
            </x:Array>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="StaticItemStyle" TargetType="MenuItem">
</Style>

在代码中:

public class MyStyleSelector : StyleSelector
    {
        public override Style SelectStyle(object item, DependencyObject container)
        {
            var itemsControl = ItemsControl.ItemsControlFromItemContainer(container);
            if (item is MyObject)
                return (Style)itemsControl.FindResource("DynamicItemStyle");
            else 
                return (Style)itemsControl.FindResource("StaticItemStyle");
        }
    }
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            MyObject dynamicObject = new MyObject();
            dynamicObject.Title = "dynamic1";
            Windows.Add(dynamicObject);
            Windows.Add(new MyObject() { Title = "dynamic2" });
        }

        private ObservableCollection<MyObject> _windows = new ObservableCollection<MyObject>();


        public ObservableCollection<MyObject> Windows
        {
            get { return _windows; }
            set { _windows = value; }
        }
    }

    public class MyObject
    {
        public string Title { get; set; }
    }

`

【讨论】:

  • 我一直在使用另一种方式来实现我的目标,但无论如何你的代码通过一些调整来完成这项工作。我希望它也能帮助其他人。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多