これは少し時間がかかるかもしれませんが、ここに入ります。私は、MVVMパターン(基本的に私の「本当の」アプリのコードの愚かなバージョン)を使って、小さなウィザードスタイルのサンプルアプリケーションを作成しました。このアプリでは、メインウィンドウは、ビューモデルのList < ..>から移動し、各ビューモデルは関連付けられたビューを表示します。私は本質的に同じ2つのビューモデルクラスを持ち、同じビューを表示します。MVVM IValueConverter浮動小数点数を求めるときに空の文字列引数を取得するメソッドを変換します。
ビューでは、コンボボックスにfloatの配列が設定されています。 SelectedItemは、ビューモデルのfloatプロパティにバインドされています。コンボボックスのテンプレートを作成して各アイテムをTextBlockとして表示し、テキストは浮動小数点値をとり、値コンバータを通過します。
問題は、ビューモデル間で前後に切り替えると、すべてのビューモデルが切り替わる限り、すべて同じクラスになります。現在のページを別のビューモデルのインスタンスに変更すると、値コンバータのConvertは長さゼロの文字列である 'value'パラメータで呼び出されます。それまでのところ、Convertは浮動小数点数で呼び出されていましたが、私は期待していました。
私の質問:ビューモデルクラスを切り替える場合にのみコンバータが空の文字列で呼び出されるのはなぜですか?
メインウィンドウのXAMLとビューモデル、および各 "ページ"に表示されるビュー/ビューモデルを添付します。メインウィンドウビューモデルには、PageViewModelの2つのインスタンスと、OtherViewModelの2つのインスタンスを含むリストがあります。私は最初の2つの間で前後に切り替えることができ、値コンバータはfloat値で呼び出されるだけです。最初のOtherViewModelインスタンスに切り替えると、コンバーターは値として空の文字列を持つ「余分な」呼び出しを取得します。
コードスニペット:
メインウィンドウ
<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="< Back" VerticalAlignment="Top" HorizontalAlignment="Left" Command="{Binding BackCommand}" /> <Button Margin="85,115,0,0" Width="75" Content="Next >" VerticalAlignment="Top" HorizontalAlignment="Left" Command="{Binding NextCommand}" />
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つのインスタンスに続く1つのビューモデルの2インスタンス。
ページビュー
<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
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); } }
注:私は変換メソッドで例外を削除することができ、すべてが正常に動作するようです。しかし、私はなぜこれが起こっているのか知りたいです。予想される浮動小数点数の代わりにコンバーターが空の文字列を取得するのはなぜですか?また、ビューモデルを切り替えるときだけです。
洞察力があれば幸いです。前もって感謝します... ジョー
DataTemplateで浮動するように設定しようとしましたか? – Silvermind
Silvermind、DataType = "{x:Type sys:Single}"をPageViewのDataTemplate行に追加しようとしましたが、それでも同じ問題が発生します。私はまだ値として空の文字列でコンバータを呼び出します。 –