2017-05-24 2 views
0

Ich entwickle eine WPF-Anwendung mit caliburn.micro MVVM-Framework .. Um einen Suchbildschirm zu entwickeln, muss ich Felder dynamisch in die Ansicht laden, basierend auf Modelleigenschaften.MVVM Felder dynamisch in Ansicht hinzufügen

Betrachten unten Ansicht und Ansicht Modell:

  • SearchViewModel
  • Suche

Nehmen wir an, T eine Art von Produkt in folgenden Beispiel.

public class SearchViewModel<T> 
{ 
    public T Item{get;set;} 
} 

public class Product 
{ 
    public int Id{get;set;} 
    public string Name{get;set;} 
    public string Description{get;set;} 
} 

Ich habe eine Benutzersteuerung namens SearchView.xaml mit keinen Inhalten darauf. Wenn die Ansicht geladen wird, sollten neue Felder zur Ansicht hinzugefügt werden, und das Feld sollte an die Eigenschaften gebunden werden.

Gemäß dem obigen Codebeispiel gibt es in der Product-Klasse 3 öffentliche Eigenschaften, daher sollten der Ansicht 3 TextBoxen dynamisch hinzugefügt werden. Wenn der Benutzer Daten in das Textfeld eingibt, sollte die entsprechende Eigenschaft aktualisiert werden.

Ist das möglich? Können mir dazu Experten anhand von Beispielen helfen?

+0

Also im Grunde wollen Sie einen Text pro öffentlichem Eigentum des Typ T generieren? – mm8

+0

@ mm8 Ja, Sie haben Recht! – Rahul

+0

Ich denke, Sie wissen, wie Sie den DataContext der Sicht auf ein SearchViewModel setzen? – mm8

Antwort

1

Ich würde vorschlagen, anders zu gehen. Anstatt über das dynamische Hinzufügen von Eigenschaften zu einer Ansicht/einem Modell nachzudenken, würde ich über das Hinzufügen von Informationen über diese Eigenschaften zu einer Liste auf dem Ansichtsmodell nachdenken. Diese Liste wäre dann an eine ItemsControl mit einer Vorlage gebunden, die wie eine TextBox aussieht.

Ihr Ansichtsmodell hätte also eine Eigenschaft für das "Ding", das Sie untersuchen möchten. Verwenden Sie im Setter für diese Eigenschaft reflection, um die Eigenschaften aufzulisten, an denen Sie interessiert sind, und fügen Sie der Liste der Eigenschaften mit der Bindung eine Instanz einer beliebigen Klasse FieldInfo hinzu (die Sie erstellen).

Dies hat den Vorteil, dass auch alle MVVM-kompatiblen Geräte kompatibel sind. Es ist nicht erforderlich, Steuerelemente mit Ihrem eigenen Code dynamisch zu erstellen.


Das folgende Beispiel verwendet meine eigene MVVM-Bibliothek (als nuget Paket) statt caliburn.micro, aber es sollte ähnlich genug sein, um die Grundidee zu folgen. Der vollständige Quellcode des Beispiels kann von this BitBucket repo heruntergeladen werden.

Wie Sie in den enthaltenen Screenshots sehen können, werden die Suchfelder dynamisch in der Ansicht ohne Code in der Ansicht erstellt. Alles wird auf dem Viewmodel gemacht. Dies ermöglicht Ihnen auch einen einfachen Zugriff auf die Daten, die der Benutzer eingibt.

Der Blick-Modell:

namespace DynamicViewExample 
{ 
    class MainWindowVm : ViewModel 
    { 
     public MainWindowVm() 
     { 
      Fields = new ObservableCollection<SearchFieldInfo>(); 
      SearchableTypes = new ObservableCollection<Type>() 
           { 
            typeof(Models.User), 
            typeof(Models.Widget) 
           }; 

      SearchType = SearchableTypes.First(); 
     } 

     public ObservableCollection<Type> SearchableTypes { get; } 
     public ObservableCollection<SearchFieldInfo> Fields { get; } 


     private Type _searchType; 

     public Type SearchType 
     { 
      get { return _searchType; } 
      set 
      { 
       _searchType = value; 
       Fields.Clear(); 
       foreach (PropertyInfo prop in _searchType.GetProperties()) 
       { 
        var searchField = new SearchFieldInfo(prop.Name); 
        Fields.Add(searchField); 
       } 
      } 
     } 

     private ICommand _searchCommand; 

     public ICommand SearchCommand 
     { 
      get { return _searchCommand ?? (_searchCommand = new SimpleCommand((obj) => 
      { 
       WindowManager.ShowMessage(String.Join(", ", Fields.Select(f => $"{f.Name}: {f.Value}"))); 
      })); } 
     } 
    } 
} 

Die SearchFieldInfo Klasse:

namespace DynamicViewExample 
{ 
    public class SearchFieldInfo 
    { 
     public SearchFieldInfo(string name) 
     { 
      Name = name; 
     } 

     public string Name { get; } 

     public string Value { get; set; } = ""; 
    } 
} 

Aussicht:

<Window 
    x:Class="DynamicViewExample.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:local="clr-namespace:DynamicViewExample" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    Title="MainWindow" 
    Width="525" 
    Height="350" 
    d:DataContext="{d:DesignInstance local:MainWindowVm}" 
    mc:Ignorable="d"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto" /> 
      <RowDefinition Height="*" /> 
      <RowDefinition Height="Auto" /> 
     </Grid.RowDefinitions> 
     <ComboBox 
      Grid.Row="0" 
      ItemsSource="{Binding Path=SearchableTypes}" 
      SelectedItem="{Binding Path=SearchType}" /> 
     <ItemsControl Grid.Row="1" ItemsSource="{Binding Path=Fields}"> 
      <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <StackPanel Orientation="Horizontal"> 
         <TextBlock Text="{Binding Path=Name}" /> 
         <TextBox Width="300" Text="{Binding Path=Value}" /> 
        </StackPanel> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
     </ItemsControl> 
     <Button Grid.Row="2" Command="{Binding Path=SearchCommand}">Search</Button> 
    </Grid> 
</Window> 

Die Modellklassen:

class User 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string PhoneNumber { get; set; } 
    public string Id { get; set; } 
} 

class Widget 
{ 
    public string ModelNumber { get; set; } 
    public string Name { get; set; } 
    public string Description { get; set; } 
} 

searching a Widget model searching User model

+0

Intresting, Könnten Sie das bitte mit etwas Code erklären? – Rahul

+0

Ich brauche etwas Zeit, um etwas vorzubereiten. –

+0

Hier ist ein Beispielprojekt, das ich erstellt habe, damit Sie es betrachten können. Ich bin dabei, meine Antwort mit den relevantesten Teilen zu aktualisieren. https://bitbucket.org/BradleyUffner/wpf-dynamic-search-fields-example/src –

1

Hier ist ein einfaches Beispiel, wie Sie eine TextBox pro öffentliche Eigenschaft der T in der Steuerung mit Reflektion generieren können.

SearchView.xaml:

<Window x:Class="WpfApplication4.SearchView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:WpfApplication4" 
     mc:Ignorable="d" 
     Title="SearchView" Height="300" Width="300"> 
    <StackPanel x:Name="rootPanel"> 

    </StackPanel> 
</Window> 

SearchView.xaml.cs:

public partial class SearchView : UserControl 
{ 
    public SearchView() 
    { 
     InitializeComponent(); 
     DataContextChanged += SearchView_DataContextChanged; 
     DataContext = new SearchViewModel<Product>(); 
    } 

    private void SearchView_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) 
    { 
     if (e.NewValue != null) 
     { 
      Type genericType = e.NewValue.GetType(); 
      //check the DataContext was set to a SearchViewModel<T> 
      if (genericType.GetGenericTypeDefinition() == typeof(SearchViewModel<>)) 
      { 
       //...and create a TextBox for each property of the type T 
       Type type = genericType.GetGenericArguments()[0]; 
       var properties = type.GetProperties(); 
       foreach(var property in properties) 
       { 
        TextBox textBox = new TextBox(); 
        Binding binding = new Binding(property.Name); 
        if (!property.CanWrite) 
         binding.Mode = BindingMode.OneWay; 
        textBox.SetBinding(TextBox.TextProperty, binding); 

        rootPanel.Children.Add(textBox); 
       } 
      } 
     } 
    } 
} 

Die andere Option wird offensichtlich sein, eine "statische" für jede Art von T Ansicht zu erstellen und definieren Sie wie gewohnt die TextBox Elemente im XAML-Markup.

Verwandte Themen