【问题标题】:Databinding not updating in a WinRT Flyout数据绑定未在 WinRT Flyout 中更新
【发布时间】:2014-02-08 15:29:53
【问题描述】:

我有一个 Flyout(相关部分如下):

<Flyout x:Key="flyoutAverage" FlyoutPresenterStyle="{StaticResource flyoutPresenter}" Closed="Flyout_Closed">
  <Grid>
    <TextBox Grid.Row="1" Grid.Column="0" Text="{Binding One, Mode=TwoWay}" InputScope="Number" Margin="5,0" />
    <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Two, Mode=TwoWay}" InputScope="Number" Margin="5,0"  />
    <TextBox Grid.Row="1" Grid.Column="2" Text="{Binding Three, Mode=TwoWay}" InputScope="Number" Margin="5,0"  />
    <TextBlock Grid.Row="1" Grid.Column="3" FontSize="18" VerticalAlignment="Center" Text="{Binding Average}" />
 </Grid>
</Flyout>

通过此按钮显示:

<StackPanel Orientation="Horizontal" DataContext="{Binding Neck}">
  ...
  <Button Flyout="{StaticResource flyoutAverage}">Enter</Button>
</StackPanel>

按钮(和 Flyout)的数据上下文是这个对象的一个​​实例:

public decimal One
{
  get { return m_One; }
  set { m_One = value; PropChanged("First"); PropChanged("Average"); }
}
public decimal Two
{
  get { return m_Two; }
  set { m_Two = value; PropChanged("Second"); PropChanged("Average"); }
}
public decimal Three
{
  get { return m_Three; }
  set { m_Three = value; PropChanged("Third"); PropChanged("Average"); }
}
public decimal Average
{
  get
  {
    return (One + Two + Three) / 3;
  }
}

预期的行为是当用户点击一个按钮时,他们会看到:

用户在每个文本框中输入值,“平均值”文本块会自动更新为平均值。

文本框填充了正确的值,但永远不会被推回对象。当我关闭 Flyout 并重新打开它时,这些值将保留。好像绑定模式是单向,当它明确设置为双向时。

有什么想法吗?还是我做错了?

【问题讨论】:

    标签: c# data-binding windows-runtime flyout


    【解决方案1】:

    在进行TwoWay 绑定时,如果不处理数据转换,则不能直接从TextBox 绑定到decimalTextBox Text 属性是字符串类型。需要一个像这样的简单转换器(使用IValueConverter (reference)):

    public class DecimalConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, 
                              object parameter, string language)
        {
            return value.ToString();
        }
    
        public object ConvertBack(object value, Type targetType, 
                                  object parameter, string language)
        {
            decimal d;
            if (value is string)
            {
                if (decimal.TryParse((string)value, out d))
                {
                    return d;
                }
            }
            return 0.0;
        }
    }
    

    作为Resource

    <local:DecimalConverter x:Key="decimalConverter" />
    

    那么,在使用中:

    <TextBox Grid.Row="1" Grid.Column="0" 
            Text="{Binding One, Mode=TwoWay, 
                     Converter={StaticResource decimalConverter}}" 
            InputScope="Number" Margin="5,0" />
    

    InputScope 只是对 Windows 的一个建议,即当字段获得焦点时,默认情况下应该显示什么键盘。它不会阻止不需要的键(或字母字符)。

    另外,请务必致电PropChanged 并使用正在更改的属性名称。它们在您的代码中是错误的。

    当绑定在 XAML/WPF 应用程序中未按预期工作时,您应该始终使用的一件事是检查 Visual Studio Output 窗口是否有错误。例如,您会看到如下内容:

    错误:无法将值从目标保存回源。 BindingExpression: Path='Two' DataItem='Win8CSharpTest.NeckData, Win8CSharpTest,版本=1.0.0.0,文化=中性, PublicKeyToken=null';目标元素是 'Windows.UI.Xaml.Controls.TextBox' (Name='null');目标属性是 “文本”(输入“字符串”)。

    【讨论】:

    • 我的 PropChanged 使用的是我之前使用的属性名称。改变了。另外,关于输出窗口的好提示。
    • DecimalConverter 是诀窍。想知道为什么我在 WinRT 而不是 WP8 上需要它吗?
    • 遗憾的是,WinRT 没有绑定转换器——直接数据绑定到其他语言的双属性时需要它。
    【解决方案2】:

    只是为了分享将来是否有人遇到此问题,我使用了上述转换器,但正在绞尽脑汁想为什么转换不起作用。碰巧的是,我的语言环境的小数分隔符是“,”而不是“。”。因此,为了解决这个问题,我对转换器进行了如下修改:

    public class DecimalConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { return value.ToString(); } public object ConvertBack(object value, Type targetType, object parameter, string language) { if (value is string) { decimal d; var formatinfo = new NumberFormatInfo(); formatinfo.NumberDecimalSeparator = "."; if (decimal.TryParse((string)value, NumberStyles.Float, formatinfo, out d)) { return d; } formatinfo.NumberDecimalSeparator = ","; if (decimal.TryParse((string)value, NumberStyles.Float, formatinfo, out d)) { return d; } } return 0.0; } }

    【讨论】:

      【解决方案3】:

      我更喜欢处理字符串格式化和绑定的更通用的解决方案:

       public class StringFormatConverter : IValueConverter
      {
          public object Convert(object value, Type targetType, object parameter, string language)
          {
              if (value == null)
              {
                  return string.Empty;
              }
              return string.Format((parameter as string) ?? "{0}", value);
          }
      
          public object ConvertBack(object value, Type targetType, object parameter, string language)
          {
              if (string.IsNullOrEmpty(System.Convert.ToString(value)))
              {
                  if (targetType.IsNullable())
                  {
                      return null;
                  }
                  return 0;
              }
      
              if (targetType == typeof (double))
              {
                  return System.Convert.ToDouble(value);
              }
              if (targetType == typeof(decimal))
              {
                  return System.Convert.ToDecimal(value);
              }
              if (targetType == typeof(int))
              {
                  return System.Convert.ToInt16(value);
              }
              if (targetType == typeof(Int32))
              {
                  return System.Convert.ToInt32(value);
              }
              return value;
          }
      }
      

      用法:

      <TextBox InputScope="Number" Text="{Binding Path=Model.SalesPrice, Mode=TwoWay, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:N2}'}">
      

      这会将显示值和输入值都转换回源值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-03-04
        • 1970-01-01
        • 2012-11-07
        • 1970-01-01
        • 1970-01-01
        • 2019-07-28
        • 1970-01-01
        相关资源
        最近更新 更多