【问题标题】:Binding menu item IsChecked to a setting将菜单项 IsChecked 绑定到设置
【发布时间】:2016-07-14 23:57:52
【问题描述】:

这不正常:

<MenuItem x:Uid="MenuItem_12" Header="400%" IsCheckable="True"
          IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={StaticResource IsValidZoomFactor}, ConverterParameter='400'}"/>

在我的Settings 中有一个整数ZoomFactor。设置设置为 Public 和范围 User

在我的 XAML 顶部,我有一个命名空间:

xmlns:Properties="clr-namespace:OCLMEditor.Properties"

这是我的ValueConverter

using System;
using System.Globalization;
using System.Windows.Data;

namespace OCLMEditor.ValueConverters
{
    [ValueConversion(typeof(int), typeof(bool))]
    public class IsCurrentZoomFactor : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            int desiredZoomFactor = (int)value;
            int currentZoomFactor = (int)parameter;

            return desiredZoomFactor == currentZoomFactor;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

但我得到一个错误:

1>D:\My Programs\OCLMEditor\OCLMEditor\MainWindow.xaml(143,35):错误 MC3044:在 MarkupExtension 表达式的结束“}”之后不允许使用文本“}”。第 143 行位置 35。

我还有其他几个菜单项:

<MenuItem x:Uid="MenuItem_13" Header="300%" IsCheckable="True"/>
<MenuItem x:Uid="MenuItem_14" Header="250%" IsCheckable="True"/>
<MenuItem x:Uid="MenuItem_15" Header="200%" IsCheckable="True"/>
<MenuItem x:Uid="MenuItem_16" Header="175%" IsCheckable="True"/>
<MenuItem x:Uid="MenuItem_17" Header="150%" IsCheckable="True"/>
<MenuItem x:Uid="MenuItem_18" Header="125%" IsCheckable="True"/>

我不确定我的做法是否正确,但我的想法是:

  1. 将 Settings.ZoomFactor 值传递给转换器。
  2. 将预期的缩放系数值传递给转换器。
  3. 比较它们,如果它们相同,则将其设置为选中。

此外,目前它已“更改”,因此另一个缩放系数,设置要更新。我认为绑定到“设置”是正确的方法。但是有错误。

我确认错误出现在IsChecked 行:

更新错误:

这个位本身没有视觉错误:

<MenuItem x:Uid="MenuItem_12" Header="400%" IsCheckable="True"
          IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor}"/>

所以出错的是转换器/值的引入。

现在,我不得不更换我的转换器:

using System;
using System.Globalization;
using System.Windows.Data;

namespace OCLMEditor.ValueConverters
{
    [ValueConversion(typeof(int), typeof(bool))]
    public class IsCurrentZoomFactor : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            int currentZoomFactor = (int)value;
            string strDesiredZoomFactor = (string)parameter;
            int desiredZoomFactor = int.Parse(strDesiredZoomFactor);
            return desiredZoomFactor == currentZoomFactor;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

因为我们传递 '400' 它是一个字符串。所以我必须将它转换为整数。如果我删除 ' ',它将不接受将其作为整数传递。

【问题讨论】:

  • 您确定 MenuItem 是第 143 行/第 35 位的内容吗?该错误表示绑定中的孤立的右花括号或其他:例如Foo="{Binding Bar}}"
  • @EdPlunkett 大括号似乎是正确的。
  • 它们看起来是正确的。这不是单引号,它们在你有它们的地方很好。那条线上没有其他东西,对吧?您是否清理了解决方案,重新启动 VS 并构建?当 XAML 编辑器似乎失去理智时,这总是值得尝试的。
  • 我认为那里没有任何“反向转换”。您有一个命令或设置缩放因子的东西,当缩放因子发生变化时,菜单项会自行检查或取消选中。没有任何事情朝着另一个方向发展。您可以执行一个命令,或者只是一个它们都共享的单击事件,将每个 MenuItem 的 Tag 属性设置为适当的缩放系数;在点击处理程序中,Settings.Default.ZoomFactor = Int32.Parse((String) ((MenuItem)sender).Tag); 不是纯粹的 MVVM,但你不必总是对这些东西狂热。
  • 在下面我的答案末尾添加了一个更新——它不是缩放因子转换器,它确实是一个普遍有用的整数相等检查转换器。

标签: c# wpf xaml


【解决方案1】:

您的问题是 ConverterParameter。写出不带撇号的参数,如

... ConverterParameter=400}"/>

另外,您必须使用 Convert 来获取整数值,例如

int desiredZoomFactor = Convert.ToInt16(value);

【讨论】:

  • 谢谢。如果我删除撇号,现在它会在输出窗口中告诉我“指定的演员表无效”。
  • 你能发一个截图吗?
  • 我已经添加了屏幕截图。
  • 查看更新的问题。我不得不恢复到“400”并更改转换器逻辑。
  • 我没有意识到你已经编辑了你的答案。我会给它一个赞成票,但已经接受了另一个答案。
【解决方案2】:

似乎这里的问题与 Binding.ConverterParameter 是一个字符串这一事实有关,因为 XAML 解析器无法知道预期的类型。

这是一种使用强类型参数(或多个参数,如果您愿意)重写值转换器的方法。如果您可以将参数类型检查从代码中的运行时错误转移到 IDE 中的设计时消息,那总是一个胜利。

public class IsCurrentZoomFactor : MarkupExtension, IValueConverter
{
    public int DesiredZoomFactor { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int currentZoomFactor = (int)value;
        return DesiredZoomFactor == currentZoomFactor;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

并像这样使用它。请注意,我们没有创建 IsCurrentZoomFactor 的实例作为资源。因为它是一个MarkupExtension,所以我们在我们使用它的地方实例化它,我们也在那里初始化它的参数属性。这样做的好处是 XAML 解析器知道 DesiredZoomFactor 是一个整数。

你会这样使用它:

<MenuItem 
    x:Uid="MenuItem_12" Header="400%" IsCheckable="True"
    IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={local:IsCurrentZoomFactor DesiredZoomFactor=400}}"
    />

这非常方便,因为它使价值转换器自我记录。当您在 XAML 中键入 {local:IsCurrentZoomFactor 时,XAML 编辑器会为您提供其属性列表:

这比在编写转换器六个月或两年后试图记住参数是什么要好。如果属性类型是enum,您甚至会得到一个可供选择的值列表。

顺便说一下,我将重命名这个转换器及其参数,以反映一个事实,即如果一个整数等于另一个整数,它实际上正在返回 true:

Converter={local:IsIntegerEqual To=400}

【讨论】:

    【解决方案3】:

    感谢您的帮助。我现在有这个工作。

    所以转换器看起来像这样:

    using System;
    using System.Globalization;
    using System.Windows.Data;
    
    namespace OCLMEditor.ValueConverters
    {
        [ValueConversion(typeof(int), typeof(bool))]
        public class IsCurrentZoomFactor : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                int currentZoomFactor = (int)value;
                string strDesiredZoomFactor = (string)parameter;
                int desiredZoomFactor = int.Parse(strDesiredZoomFactor);
                return desiredZoomFactor == currentZoomFactor;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                return int.Parse((string)parameter);
                //throw new NotImplementedException();
            }
        }
    }
    

    还有 XAML:

    <MenuItem x:Uid="MenuItem_12" Header="400%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={StaticResource IsCurrentZoomFactor}, ConverterParameter='400'}"/>
    <MenuItem x:Uid="MenuItem_13" Header="300%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={StaticResource IsCurrentZoomFactor}, ConverterParameter='300'}"/>
    <MenuItem x:Uid="MenuItem_14" Header="250%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={StaticResource IsCurrentZoomFactor}, ConverterParameter='250'}"/>
    <MenuItem x:Uid="MenuItem_15" Header="200%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={StaticResource IsCurrentZoomFactor}, ConverterParameter='200'}"/>
    <MenuItem x:Uid="MenuItem_16" Header="175%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={StaticResource IsCurrentZoomFactor}, ConverterParameter='175'}"/>
    <MenuItem x:Uid="MenuItem_17" Header="150%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={StaticResource IsCurrentZoomFactor}, ConverterParameter='150'}"/>
    <MenuItem x:Uid="MenuItem_18" Header="125%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={StaticResource IsCurrentZoomFactor}, ConverterParameter='125'}"/>
    <MenuItem x:Uid="MenuItem_19" Header="100%" IsCheckable="True" InputGestureText="CTRL + 0"  IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={StaticResource IsCurrentZoomFactor}, ConverterParameter='100'}">
        <MenuItem.InputBindings>
            <KeyBinding x:Uid="KeyBinding_9" Key="D0"  Modifiers="Ctrl"/>
        </MenuItem.InputBindings>
    </MenuItem>
    <MenuItem x:Uid="MenuItem_20" Header="75%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={StaticResource IsCurrentZoomFactor}, ConverterParameter='75'}"/>
    <MenuItem x:Uid="MenuItem_21" Header="50%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={StaticResource IsCurrentZoomFactor}, ConverterParameter='50'}"/>
    <Separator x:Uid="Separator_8"/>
    <MenuItem x:Uid="MenuItem_22" Header="Custom..."/>
    

    至少现在设置已正确保存。我知道我还有更多工作要做(比如将点击绑定到命令)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-15
      • 2017-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多