MVVM IValueConverter Convert方法在期望浮点数时获取空字符串参数 [英] MVVM IValueConverter Convert method getting empty string argument when expecting a float

查看:42
本文介绍了MVVM IValueConverter Convert方法在期望浮点数时获取空字符串参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这可能会有点长,但是可以了.我使用MVVM模式(基本上是我的真实"应用程序中的代码的精简版)创建了一个小型的向导式示例应用程序.在该应用程序中,主窗口从视图模型的列表移至其中,每个视图模型都显示其关联的视图.我有2个视图模型类,它们基本上是相同的,并且它们显示相同的视图.

This may get a tad long, but here goes. I have created a small, wizard-style sample app using the MVVM pattern (basically a dumbed-down version of the code in my "real" app). In this app, the main window moves from through a List<..> of view models, with each view model displaying its associated view. I have 2 view model classes that are essentially identical, and they display the same view.

在视图上是一个组合框,其中填充了一个float数组. SelectedItem绑定到视图模型上的float属性.我为组合框创建了一个模板,以将每个项目显示为TextBlock,其中文本采用浮点值并通过值转换器.

On the view is a combo box, populated with an array of float. The SelectedItem is bound to a float property on the view model. I have created a template for the combo box to display each item as a TextBlock, with the text taking the float value and going through a value converter.

问题是,当我在视图模型之间来回切换时,只要我切换到的每个视图模型都属于同一类,所有方法都可以正常工作.一旦我将当前页面更改为其他视图模型的实例,就将使用值"参数(即长度为零的字符串)调用值转换器的转换".直到我想到,直到那时,Convert才被调用为浮点数.

The problem, when I switch back and forth between view models, all works fine as long as every view model I switch to is of the same class. As soon as I change the current page to an instance of a different view model, the value converter's Convert gets called with a 'value' parameter that is a zero-length string. Up til then, Convert was only being called with a float, as I would expect.

我的问题:为什么仅在切换视图模型类的情况下才使用空字符串调用转换器?

My question : why is the converter being called with the empty string ONLY in the case of switching view model classes?

我将附加主窗口XAML和视图模型,以及为每个页面"显示的视图/视图模型.您会注意到,主窗口视图模型有一个列表,其中包含2个PageViewModel实例和2个OtherViewModel实例.我可以在前两个罚款之间来回切换,并且只使用浮点值调用值转换器.切换到第一个OtherViewModel实例后,转换器将收到一个附加"调用,并将空字符串作为值.

I am attaching the main window XAML and view model, as well as the view/view models displayed for each "page". You'll notice that the main window view model has a list containing 2 instances of PageViewModel and 2 instances of OtherViewModel. I can switch back and forth between the first 2 fine, and the value converter only gets called with a float value. Once I switch to the first OtherViewModel instance, the converter gets an "extra" call with an empty string as the value.

代码段:

  1. MainWindow

  1. MainWindow

<Grid.Resources>
    <DataTemplate DataType="{x:Type local:PageViewModel}">
        <local:PageView />
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:OtherViewModel}">
        <local:PageView />
    </DataTemplate>
</Grid.Resources>

<!-- Page -->
<ContentControl Margin="5,5,5,35"
                Height="100"
                IsTabStop="False"
                Content="{Binding CurrentPage}" />

<!-- Commands -->
<Button Margin="5,115,0,0" 
        Width="75"
        Content="&lt; Back"
        VerticalAlignment="Top"
        HorizontalAlignment="Left"
        Command="{Binding BackCommand}" />

<Button Margin="85,115,0,0"
        Width="75"
        Content="Next &gt;"
        VerticalAlignment="Top"
        HorizontalAlignment="Left"
        Command="{Binding NextCommand}" />

  • MainWindowViewModel

  • MainWindowViewModel

        public MainWindowViewModel()
        {
           m_pages = new List<BaseViewModel>();
           m_pages.Add(new PageViewModel(1, 7f));
           m_pages.Add(new PageViewModel(2, 8.5f));
           m_pages.Add(new OtherViewModel(3, 10f));
           m_pages.Add(new OtherViewModel(4, 11.5f));
           m_currentPage = m_pages.First();
    
           m_nextCommand = new BaseCommand(param => this.OnNext(), param => this.EnableNext());
           m_backCommand = new BaseCommand(param => this.OnBack(), param => this.EnableBack());
        }
    
        // Title
    
        public string Title
        {
           get
           {
              return (CurrentPage != null) ? CurrentPage.Name : Name;
           }
        }
    
        // Pages
    
        BaseViewModel m_currentPage = null;
        List<BaseViewModel> m_pages = null;
    
        public BaseViewModel CurrentPage
        {
           get
           {
              return m_currentPage;
           }
           set
           {
              if (value == m_currentPage)
                 return;
              m_currentPage = value;
              OnPropertyChanged("Title");
              OnPropertyChanged("CurrentPage");
           }
        }
    
        // Back
    
        ICommand m_backCommand = null;
        public ICommand BackCommand
        {
           get
           {
              return m_backCommand;
           }
        }
        public void OnBack()
        {
           CurrentPage = m_pages[m_pages.IndexOf(CurrentPage) - 1];
        }
        public bool EnableBack()
        {
           return CurrentPage != m_pages.First();
        }
    
        // Next
    
        ICommand m_nextCommand = null;
        public ICommand NextCommand
        {
           get
           {
              return m_nextCommand;
           }
        }
        public void OnNext()
        {
           CurrentPage = m_pages[m_pages.IndexOf(CurrentPage) + 1];
        }
        public bool EnableNext()
        {
           return CurrentPage != m_pages.Last();
        }
     }
    

  • 请注意一个视图模型的2个实例,然后是另一个视图模型的2个实例.

    Notice the 2 instance of one view model followed by 2 instances of the other.

    1. PageView

    1. PageView

    <Grid.Resources>
        <x:Array x:Key="DepthList"
                 Type="sys:Single">
            <sys:Single>7</sys:Single>
            <sys:Single>8.5</sys:Single>
            <sys:Single>10</sys:Single>
            <sys:Single>11.5</sys:Single>
        </x:Array>
        <local:MyConverter x:Key="MyConverter" />
    </Grid.Resources>
    
    <TextBlock Text="Values:"
               Margin="5,5,0,0">
    </TextBlock>
    
    <ComboBox Width="100"
              Height="23"
              VerticalAlignment="Top"
              HorizontalAlignment="Left"
              Margin="5,25,0,0"
              DataContext="{Binding}"
              SelectedItem="{Binding Depth}"
              ItemsSource="{Binding Source={StaticResource DepthList}}">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Converter={StaticResource MyConverter}}" />
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>
    

  • PageViewModel/OtherViewModel/MyConverter

  • PageViewModel/OtherViewModel/MyConverter

       public class PageViewModel : BaseViewModel
       {
          public PageViewModel(int index, float depth)
          {
             Depth = depth;
             Name = "Page #" + index.ToString();
          }
    
          public float Depth
          {
             get;
             set;
          }
       }
    
       public class OtherViewModel : BaseViewModel
       {
          public OtherViewModel(int index, float depth)
          {
             Depth = depth;
             Name = "Other #" + index.ToString();
          }
    
          public float Depth
          {
             get;
             set;
          }
       }
    
       [ValueConversion(typeof(DateTime), typeof(String))]
       public class MyConverter : IValueConverter
       {
          public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
          {
             Debug.WriteLine("IValueConverter.Convert : received a " + value.GetType().Name);
    
             string text = "";
             if (value is float)
             {
                text = value.ToString();
             }
             else
             {
                throw new ArgumentException("MyConverter : input value is NOT a float.");
             }
    
             return text;
          }
    
          public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
          {
             return float.Parse(value as string);
          }
       }
    

  • 注意:我可以在Convert方法中删除该异常,并且一切似乎都可以正常工作.但是,我想知道为什么会这样.为什么只有在切换视图模型时,转换器才会获取空字符串而不是预期的float?

    Note: I can remove the exception in the Convert method, and everything seems to work fine. But, I would like to know why this is happening. Why is the converter getting an empty string instead of the expected float, and only when we switch view models?

    任何见解将不胜感激.提前致谢... 乔

    Any insights would be greatly appreciated. Thanks in advance... Joe

    推荐答案

    我遇到了同样的问题(用枚举而不是浮点数).

    I've had the same issue (with an enum instead of a float).

    当视图关闭时,组合框选择被清空.您可以通过处理SelectionChanged事件并检查SelectionChangedEventArgs RemovedItems集合来进行检查. 结束于将String.Empty传递到您的ValueConverter中.

    When the View is closed the ComboBox Selection is emptied. You can check this by handling SelectionChanged event and inspecting the SelectionChangedEventArgs RemovedItems collection. This ends in String.Empty being passed into your ValueConverter.

    就我而言,我修改了ValueConverter.Convert以允许将string.Empty作为有效值,并返回string.Empty. 这是我使用的代码:

    In my case, I have modified the ValueConverter.Convert to allow string.Empty as a valid value, and return string.Empty. This is the code I used:

    // When view is unloaded, ComboBox Selection is emptied and Convert is passed string.Empty 
    // Hence we need to handle this conversion
    if (value is string && string.IsNullOrEmpty((string)value))
    {
        return string.Empty;
    }
    

    这篇关于MVVM IValueConverter Convert方法在期望浮点数时获取空字符串参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆