Dieses kann ein wenig lang erhalten, aber geht hier. Ich habe eine kleine Beispielanwendung im Wizard-Stil erstellt, die das MVVM-Muster verwendet (im Grunde eine abgespeckte Version des Codes in meiner "echten" App). In dieser App wird das Hauptfenster durch eine Liste der Ansichtsmodelle < ..> verschoben, wobei jedes Ansichtsmodell die zugehörige Ansicht anzeigt. Ich habe zwei Ansichtsmodellklassen, die im Wesentlichen identisch sind und dieselbe Ansicht anzeigen.MVVM IValueConverter Convert-Methode, die leeres Zeichenfolgenargument erhält, wenn man eine Hin- und Herbewegung erwartet
In der Ansicht ist ein Kombinationsfeld, bestückt mit einem Array von Float. Das SelectedItem ist an eine Float-Eigenschaft im Ansichtsmodell gebunden. Ich habe eine Vorlage für das Kombinationsfeld erstellt, um jedes Element als TextBlock anzuzeigen, wobei der Text den Gleitkommawert enthält und einen Wertkonverter durchläuft.
Das Problem, wenn ich zwischen Ansichtsmodellen hin- und herwechsle, funktioniert alles gut, solange jedes Ansichtsmodell, zu dem ich wechsle, von derselben Klasse ist. Sobald ich die aktuelle Seite in eine Instanz eines anderen Ansichtsmodells ändere, wird Convert des Wertkonverters mit einem Parameter 'value' aufgerufen, der eine Zeichenfolge mit der Länge null ist. Bis dahin wurde Convert nur mit einem Float aufgerufen, wie ich es erwarten würde.
Meine Frage: Warum wird der Konverter mit der leeren Zeichenkette ONLY aufgerufen, wenn man Klassenklassen wechselt?
Ich füge das Hauptfenster XAML an und betrachte das Modell sowie die Ansichts-/Ansichtsmodelle, die für jede "Seite" angezeigt werden. Sie werden feststellen, dass das Hauptfenstermodell eine Liste mit 2 Instanzen von PageViewModel und 2 Instanzen von OtherViewModel enthält. Ich kann zwischen den ersten beiden Strichen hin und her schalten, und der Wertwandler wird nur mit einem Float-Wert aufgerufen. Sobald ich zur ersten OtherViewModel-Instanz gewechselt habe, erhält der Konverter einen "extra" -Aufruf mit einer leeren Zeichenfolge als Wert.
-Code-Schnipsel:
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="< 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(); } }
Beachten Sie die 2 Instanz eines View-Modell durch zwei Instanzen der anderen folgte.
Page-View-
<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); } }
Hinweis: Ich habe die Ausnahme in der Methode Konvertieren entfernen können, und alles scheint gut zu funktionieren. Aber ich würde gerne wissen, warum das passiert. Warum erhält der Konverter anstelle des erwarteten Floats eine leere Zeichenfolge, und nur wenn wir View-Modelle wechseln?
Alle Einsichten würden sehr geschätzt werden. Danke im Voraus... Joe
Haben Sie versucht, DataType auf dem DataTemplate zu floaten? – Silvermind
Silvermind, ich habe gerade versucht, DataType = "{x: Geben Sie sys: Single}" zu der DataTemplate-Zeile in der PageView, und ich bekomme immer noch das gleiche Problem. Ich bekomme immer noch einen Aufruf an den Konverter mit einer leeren Zeichenfolge als Wert. –