【问题标题】:How to create a selection of bound items in a context menu in wpf?如何在 wpf 的上下文菜单中创建绑定项目的选择?
【发布时间】:2020-08-04 18:13:04
【问题描述】:

我目前正在为 WPF 中的模拟器开发前端,但在使用这个看似基本的功能时遇到了问题。

我正在尝试从上下文菜单中创建一个简单的项目选择(在本例中为图像)。一张图解释得更好一点:

我希望一次只选择/检查一个,然后此数据在我的模型中设置一个值,该值最终写入外部文件。在原型中,我将它绑定到具有双向绑定的组合框,但这对这种设计没有真正意义。

我尝试了几种不同的方法,但没有找到合适的解决方案(特别是如何控制未点击项目的 isChecked)。

我的上下文菜单 (xaml) 如下所示:

<ContextMenu>
    <MenuItem Header="PCSX2 Version" ItemsSource="{Binding Versions}">
        <MenuItem.ItemContainerStyle>
            <Style TargetType="MenuItem">
                <Setter Property="StaysOpenOnClick" Value="True" />
                <Setter Property="BindingGroup" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MenuItem}}}" />
                <EventSetter Event="Click" Handler="SetVersion" />
            </Style>
        </MenuItem.ItemContainerStyle>
    </MenuItem>
    <MenuItem Header="Config" ItemsSource="{Binding Configs}" />
    <MenuItem Header="Create Config" BindingGroup="{Binding}" Click="ShowConfigWizard"/>
</ContextMenu>

我的模型如下所示,后面的代码(SetVersion 函数)还没有多少工作。正如您在下面看到的,我尝试了一个涉及绑定元组的解决方案,但无法使其工作(ischecked 值从未更新,尽管绑定条件不再为真)。

我还尝试了基于单选按钮的解决方案(再次无法使其工作),只是将后面代码中的所有项目的检查设置为 false(无法从绑定中选择同级菜单项)。

public class GameModel : ICloneable
{
    public string Game { get; set; }
    public string Path { get; set; }
    public IEnumerable<string> Versions { get; set; }
    public IEnumerable<Tuple<string, bool>> VersionsAndStates => Versions.Select(version => new Tuple<string, bool>(version, Version == version));
    public string Version { get; set; }
    public IEnumerable<string> Configs { get; set; }
    public string Config { get; set; }
    public string CoverPath { get; set; }

    object ICloneable.Clone() => Clone();
    public GameModel Clone() => (GameModel) MemberwiseClone();
}

【问题讨论】:

    标签: c# wpf xaml contextmenu


    【解决方案1】:

    通常我只是发布了一个解决方案,然后我发现我已经很接近了,只是我对 ViewModel 的工作方式有一点疏忽。我会把我的解决方案放在下面,以防其他人有类似的问题。主要变化在于我的模型。

    public class GameModel : ICloneable, INotifyPropertyChanged
    {
        public string Game { get; set; }
        public string Path { get; set; }
        public IEnumerable<string> Versions { get; set; }
        public IEnumerable<Tuple<string, bool>> VersionsAndStates => Versions.Select(version => new Tuple<string, bool>(version, Version == version));
        private string version;
        public string Version 
        {
            get => version;
            set
            {
                version = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Version)));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(VersionsAndStates)));
            }
        }
        public IEnumerable<string> Configs { get; set; }
        public string Config { get; set; }
        public string CoverPath { get; set; }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        object ICloneable.Clone() => Clone();
        public GameModel Clone() => (GameModel) MemberwiseClone();
    }
    

    还有我的 xaml

        <ContextMenu>
            <MenuItem Header="PCSX2 Version" ItemsSource="{Binding VersionsAndStates}">
                <MenuItem.ItemContainerStyle>
                    <Style TargetType="MenuItem">
                        <Setter Property="Header" Value="{Binding Item1}" />
                        <Setter Property="IsChecked" Value="{Binding Item2, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
                        <Setter Property="StaysOpenOnClick" Value="True" />
                        <Setter Property="BindingGroup" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MenuItem}}}" />
                        <EventSetter Event="Click" Handler="SetVersion" />
                    </Style>
                </MenuItem.ItemContainerStyle>
            </MenuItem>
            <MenuItem Header="Config" ItemsSource="{Binding Configs}" />
            <MenuItem Header="Create Config" BindingGroup="{Binding}" Click="ShowConfigWizard"/>
        </ContextMenu>
    

    然后将模型上的版本设置为我后面代码中的选定标题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多