绑定菜单项IsChecked到一个设置

时间:2016-07-14 14:36:57

标签: c# wpf xaml

这样做不对:

<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。设置设置为公开,范围用户

在我的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&gt; D:\ My Programs \ OCLMEditor \ OCLMEditor \ MainWindow.xaml(143,35):error 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. 比较两者,如果它们相同,请将其设置为选中。
  4. 此外,此时它被“更改”,因此另一个缩放因子,即要更新的设置。我认为绑定到“设置”是正确的方法。但是有错误。

    我确认错误发生在IsChecked行:

    Editor

    更新错误:

    Error

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

    <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',所以它是一个字符串。所以我必须将其转换为整数。如果我删除''它将不接受将其作为整数传递。

3 个答案:

答案 0 :(得分:1)

你的问题是ConverterParameter。写一个没有撇号的参数

... ConverterParameter=400}"/>

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

int desiredZoomFactor = Convert.ToInt16(value);

答案 1 :(得分:1)

这里的麻烦似乎与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编辑器会为您提供其属性列表:

enter image description here

在你编写转换器六个月或两年后,试图记住参数是什么。如果属性类型是enum,您甚至可以获取要从中选择的值列表。

顺便说一句,我会重命名这个转换器及其参数,以反映这样一个事实:如果一个整数等于另一个整数,它真正做的是返回true:

Converter={local:IsIntegerEqual To=400}

答案 2 :(得分:0)

感谢您的帮助。我现在有点工作了。

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

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..."/>

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