2015-08-27 2 views
1

У меня есть ListBox, который связан с List от DataModel.ListBox ItemTemplate - отображает свойство, которое пользователь выбирает во время выполнения

DataModel.cs

public class DataModel 
{ 
    public string Name { get; set; } 
    public string Desc { get; set; } 
    public string Code { get; set; } 
} 

ListBox должны отображать два свойства, так что определил ItemTemplate, как показано ниже

<ListBox.ItemTemplate> 
    <DataTemplate> 
     <StackPanel Orientation="Horizontal"> 
      <TextBlock Text="{Binding Name}"></TextBlock> 
      <TextBlock Text=" - "></TextBlock> 
      <TextBlock Text="{Binding Code}"></TextBlock> 
     </StackPanel> 
    </DataTemplate> 
</ListBox.ItemTemplate> 

Моего требование заключается в том, что пользователь может выбрать, какие два свойства для отображения в ListBox во время выполнения. Я не уверен, как это достичь. Я создал образец решения для объяснения моей проблемы.

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"></RowDefinition> 
      <RowDefinition Height="*"></RowDefinition> 
     </Grid.RowDefinitions> 
     <StackPanel Orientation="Horizontal" Margin="5"> 
      <Label Content="Property One"></Label> 
      <ComboBox Name="ComboBox1" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"></ComboBox> 
      <Label Content="Property Two"></Label> 
      <ComboBox Name="ComboBox2" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"></ComboBox> 
      <Button Content="Go" Click="ButtonBase_OnClick" Margin="3"></Button> 
     </StackPanel> 
     <ListBox Grid.Row="1" ItemsSource="{Binding DataModelList}" Margin="5"> 
      <ListBox.ItemTemplate> 
       <DataTemplate> 
        <StackPanel Orientation="Horizontal"> 
         <TextBlock Text="{Binding Name}"></TextBlock> 
         <TextBlock Text=" - "></TextBlock> 
         <TextBlock Text="{Binding Code}"></TextBlock> 
        </StackPanel> 
       </DataTemplate> 
      </ListBox.ItemTemplate> 
     </ListBox> 
    </Grid> 
</Window> 

MainWindow.xaml.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Windows; 

namespace WpfApplication1 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 

      DataContext = new ViewModel(); 

     } 

     private void ButtonBase_OnClick(object sender, RoutedEventArgs e) 
     { 

     } 
    } 

    public class ViewModel 
    { 
     public List<String> DataModelProperties { get; set; } 

     public List<DataModel> DataModelList { get; set; } 

     public ViewModel() 
     { 
      DataModelList = new List<DataModel>(); 

      DataModelList.Add(new DataModel() { Name = "Name1", Code = "Code1", Desc = "Desc1" }); 
      DataModelList.Add(new DataModel() { Name = "Name2", Code = "Code2", Desc = "Desc2" }); 
      DataModelList.Add(new DataModel() { Name = "Name3", Code = "Code3", Desc = "Desc3" }); 

      DataModelProperties = typeof(DataModel).GetProperties().Select(s => s.Name).ToList(); 
     } 
    } 

    public class DataModel 
    { 
     public string Name { get; set; } 
     public string Desc { get; set; } 
     public string Code { get; set; } 
    } 
} 

Вещи, которые я попробовал

<TextBlock Text="{Binding ElementName=ComboBox1, Path=SelectedItem}"></TextBlock> 

Это просто показывает выбранное имя свойства.

ответ

0

Короче говоря, то, что я сделал, это то, что я создал 2 общедоступных свойства для привязки и изменения свойств в поля. Также я создал настраиваемый атрибут, чтобы контролировать, какие поля пользователь может выбрать. И создал класс DisplayOptions для хранения выбора и распространения его в экземплярах DataModel. Решение немного неаккуратно, считая это PoC, но я считаю, что это можно сделать:

XAML:

<Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"></RowDefinition> 
      <RowDefinition Height="*"></RowDefinition> 
     </Grid.RowDefinitions> 
     <StackPanel Orientation="Horizontal" Margin="5"> 
      <Label Content="Property One"></Label> 
      <ComboBox Name="ComboBox1" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"></ComboBox> 
      <Label Content="Property Two"></Label> 
      <ComboBox Name="ComboBox2" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"></ComboBox> 
      <Button Content="Go" Click="ButtonBase_OnClick" Margin="3"></Button> 
     </StackPanel> 
     <ListBox Grid.Row="1" ItemsSource="{Binding DataModelList}" Margin="5"> 
      <ListBox.ItemTemplate> 
       <DataTemplate> 
        <StackPanel Orientation="Horizontal"> 
         <TextBlock Text="{Binding DisplayProperty1}"></TextBlock> 
         <TextBlock Text=" - "></TextBlock> 
         <TextBlock Text="{Binding DisplayProperty2}"></TextBlock> 
        </StackPanel> 
       </DataTemplate> 
      </ListBox.ItemTemplate> 
     </ListBox> 
    </Grid> 

CS:

public partial class MainWindow : Window 
    { 
     public ViewModel model = new ViewModel(); 
     public MainWindow() 
     { 
      InitializeComponent(); 
      DataContext = model; 
     } 

     private void ButtonBase_OnClick(object sender, RoutedEventArgs e) 
     { 
      //This part has to be on the View side, but this is PoC 
      model.Opts.Prop1 = typeof(DataModel).GetFields() 
       .Where(a => a.Name == ComboBox1.SelectedItem.ToString()).FirstOrDefault(); 
      model.Opts.Prop2 = typeof(DataModel).GetFields() 
       .Where(a => a.Name == ComboBox2.SelectedItem.ToString()).FirstOrDefault(); 
      DataContext = null; 
      DataContext = model; 
     } 
    } 

    public class ViewModel 
    { 
     public DisplayOptions Opts = new DisplayOptions(); 

     public List<String> DataModelProperties { get; set; } 

     public List<DataModel> DataModelList { get; set; } 

     public ViewModel() 
     { 
      var properties = typeof(DataModel).GetFields() 
       .Where(a => a.CustomAttributes.Any(b => b.AttributeType == typeof(SwitchableAttr))); 

      //Initialising options before creating DataModel instances 
      DataModelProperties = properties.Select(s => s.Name).ToList(); 
      Opts.Prop1 = properties.ElementAt(0); 
      Opts.Prop2 = properties.ElementAt(1); 


      DataModelList = new List<DataModel>(); 
      DataModelList.Add(new DataModel() { Name = "Name1", Code = "Code1", Desc = "Desc1", options = Opts }); 
      DataModelList.Add(new DataModel() { Name = "Name2", Code = "Code2", Desc = "Desc2", options = Opts }); 
      DataModelList.Add(new DataModel() { Name = "Name3", Code = "Code3", Desc = "Desc3", options = Opts }); 
     } 
    } 

    public class DisplayOptions 
    { 
     public FieldInfo Prop1; 
     public FieldInfo Prop2; 
    } 

    public class DataModel 
    { 
     public DisplayOptions options; 
     [SwitchableAttr] 
     public string Name; 
     [SwitchableAttr] 
     public string Desc; 
     [SwitchableAttr] 
     public string Code; 

     public string DisplayProperty1 { get { return (string)options.Prop1.GetValue(this); } set { } } 
     public string DisplayProperty2 { get { return (string)options.Prop2.GetValue(this); } set { } } 
    } 

    public class SwitchableAttr : Attribute { } 
0

Я предлагаю вам управлять все вещи в отношении «динамического описания», отображаемого в ListBox в вашей модели ViewModel.

Прежде всего, ваша модель взгляда и ваша модель должны реализовать INotifyPropertyChanged. В моем примере я создал простой базовый класс, который его реализует. Мой базовый класс называется NotifyPropertyChangedImpl.

Кроме того, я добавил два свойства к модели представления: выпадающие списки для выбора свойств привязаны к этим двум свойствам.

public class ViewModel : NotifyPropertyChangedImpl 
{ 
    private string property1; 
    private string property2; 

    public List<String> DataModelProperties { get; set; } 

    public List<DataModel> DataModelList { get; set; } 

    public string Property1 
    { 
     get 
     { 
      return property1; 
     } 
     set 
     { 
      if (property1 != value) 
      { 
       property1 = value; 
       SetDynamicDescriptions(); 
      } 
     } 
    } 

    public string Property2 
    { 
     get 
     { 
      return property2; 
     } 
     set 
     { 
      if (property2 != value) 
      { 
       property2 = value; 
       SetDynamicDescriptions(); 
      } 
     } 
    } 

    public ViewModel() 
    { 
     DataModelList = new List<DataModel>(); 

     DataModelList.Add(new DataModel() { Name = "Name1", Code = "Code1", Desc = "Desc1" }); 
     DataModelList.Add(new DataModel() { Name = "Name2", Code = "Code2", Desc = "Desc2" }); 
     DataModelList.Add(new DataModel() { Name = "Name3", Code = "Code3", Desc = "Desc3" }); 

     DataModelProperties = typeof(DataModel).GetProperties().Select(s => s.Name).ToList(); 
    } 

    private void SetDynamicDescriptions() 
    { 
     PropertyInfo propertyInfo1; 
     PropertyInfo propertyInfo2; 

     Type type = typeof(DataModel); 

     if (!String.IsNullOrEmpty(property1) && !String.IsNullOrEmpty(property2)) 
     { 
      propertyInfo1 = type.GetProperty(property1); 
      propertyInfo2 = type.GetProperty(property2); 

      foreach (DataModel dataModel in DataModelList) 
      { 
       dataModel.DynamicDescription = String.Format("{0} - {1}", 
        propertyInfo1.GetValue(dataModel, null), propertyInfo2.GetValue(dataModel, null)); 
      } 
     } 
    } 
} 

Как вы можете видеть, метод SetDynamicDescriptions перестраивает DynamicsDescription каждый раз property1 или свойство2 изменения.

Я также добавил свойство к классу модели:

public class DataModel : NotifyPropertyChangedImpl 
{ 
    private string dynamicDescription; 

    public string Name { get; set; } 
    public string Desc { get; set; } 
    public string Code { get; set; } 

    public string DynamicDescription 
    { 
     get 
     { 
      return dynamicDescription; 
     } 
     set 
     { 
      if (dynamicDescription != value) 
      { 
       dynamicDescription = value; 
       OnPropertyChanged("DynamicDescription"); 
      } 
     } 
    } 
} 

Так в конце ваш XAML будет:

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto"></RowDefinition> 
     <RowDefinition Height="*"></RowDefinition> 
    </Grid.RowDefinitions> 
    <StackPanel Orientation="Horizontal" Margin="5"> 
     <Label Content="Property One"></Label> 
     <ComboBox Name="ComboBox1" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}" 
        SelectedItem="{Binding Property1}"></ComboBox> 
     <Label Content="Property Two"></Label> 
     <ComboBox Name="ComboBox2" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}" 
        SelectedItem="{Binding Property2}"></ComboBox> 

    </StackPanel> 
    <ListBox Grid.Row="1" ItemsSource="{Binding DataModelList}" Margin="5"> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding DynamicDescription}" /> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 
</Grid> 

Я надеюсь, что это может помочь вам.

0

Это не полный MVVM так вот код

public partial class MainWindow : Window 
{ 
    private ViewModel vm; 
    public MainWindow() 
    { 
     InitializeComponent(); 

     vm = new ViewModel(); 
     this.DataContext = vm; 

    } 

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e) 
    { 
     if (!string.IsNullOrEmpty(ComboBox1.Text) && !string.IsNullOrEmpty(ComboBox2.Text)) 
     { 
      vm.AddDataToModel(ComboBox1.Text, ComboBox2.Text); 
     } 
    } 
} 

public class ViewModel 
{ 
    public List<String> DataModelProperties { get; set; } 


    private ObservableCollection<DataModel> _DataModelList; 


    public ViewModel() 
    { 
     _DataModelList = new ObservableCollection<DataModel>(); 

     DataModelProperties = typeof(DataModel).GetProperties().Select(s => s.Name).ToList(); 
    } 
    public void AddDataToModel(string cmbx1Val,string cmbx2Val) 
    { 
     _DataModelList.Add(new DataModel() { Name = cmbx1Val, Code = cmbx2Val, Desc = "Desc1" }); 
    } 
    public ObservableCollection<DataModel> DataModelList 
    { 

     get 
     { 
      return _DataModelList; 
     } 
     set 
     { 
      _DataModelList = value; 

     } 

    } 



} 
Смежные вопросы