• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

替换答:一个属性,视图模型与B中的每个文本框:一个属性返回(可观察)收集

c/c++ 来源:kajovajo 3次浏览

让我们这两个枚举和模型类:替换答:一个属性,视图模型与B中的每个文本框:一个属性返回(可观察)收集

public enum A 
{ 
    A1, 
    A2, 
    A3, 
    A4 
} 
public enum B 
{ 
    B1, 
    B2, 
    B3 
} 

// model class 
public class MyModel 
{ 
    private float[][] array; 

    public MyModel() 
    { 
     array = new float[Enum.GetNames(typeof(A)).Length][]; 
     foreach (A a in EnumUtil.GetValues<A>()) 
     { 
      array[(int) a] = new float[Enum.GetNames(typeof(B)).Length]; 
     } 
    } 

    public A EnumerationA { get; set; } 
    public B EnumerationB { get; set; } 
    public float this[A a, B b] 
    { 
     get 
     { 
      return array[(int) a][(int) b]; 
     } 
     set 
     { 
      array[(int)a][(int)b] = value; 
     } 
    } 
    public float[] ArraySlice 
    { 
     get 
     { 
      return array[(int) EnumerationA]; 
     } 
    } 
} 

比方说,我们想实现一个包含一组用于枚举A的RadioButton的视图,对于每个枚举B我们都希望一个TextBox。
更改单选按钮组中的单选按钮将允许在文本框中编辑不同的值集,改回将显示先前输入的值。
enter image description here

最简单的方法,我能想到的,做到这一点是:

public class MyViewModel : ViewModelBase 
{ 
    private MyModel _myModel; 

    public A EnumerationA 
    { 
     get 
     { 
      return _myModel.EnumerationA; 
     } 
     set 
     { 
      if (Enum.Equals(_myModel.EnumerationA, value) == false) 
      { 
       _myModel.EnumerationA = value; 
       RaisePropertyChanged("EnumerationA"); 
      } 
     } 
    } 

    public float ValueB1 
    { 
     get 
     { 
      return _myModel[EnumerationA, B.B1]; 
     } 
     set 
     { 
      if (_myModel[EnumerationA, B.B1] != value) 
      { 
       _myModel[EnumerationA, B.B1] = value; 
       RaisePropertyChanged("ValueB1"); 
      } 
     } 
    } 
    // Analogously for ValueB2 and ValueB3 properties 

} 

和视图:

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto"/>  
     <RowDefinition Height="Auto"/> 

    </Grid.RowDefinitions> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="Auto"/> 
     <ColumnDefinition Width="Auto"/> 
    </Grid.ColumnDefinitions> 

    <Label Grid.Row="0" Grid.Column="0" Content="Enum A" /> 
    <StackPanel Grid.Row="0" Grid.Column="1" Orientation="Vertical"> 
    <RadioButton IsChecked="{Binding Path=EnumerationA, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:A.A1}}" Content="A1" /> 
    <RadioButton IsChecked="{Binding Path=EnumerationA, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:A.A2}}" Content="A2" /> 
    <RadioButton IsChecked="{Binding Path=EnumerationA, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:A.A3}}" Content="A3" /> 
    <RadioButton IsChecked="{Binding Path=EnumerationA, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:A.A4}}" Content="A4 /> 
    </StackPanel> 

    <Label Grid.Row="1" Grid.Column="0" Content="Float Values" /> 
    <StackPanel Grid.Row="1" Grid.Column="1" Orientation="Vertical"> 
    <StackPanel Orientation="Horizontal"><Label Content="B1" /><TextBox Text="{Binding Path=ValueB1}" /></StackPanel> 
    <StackPanel Orientation="Horizontal"><Label Content="B2" /><TextBox Text="{Binding Path=ValueB2}" /></StackPanel> 
    <StackPanel Orientation="Horizontal"><Label Content="B3" /><TextBox Text="{Binding Path=ValueB3}" /></StackPanel>  
    </StackPanel> 

</Grid> 

也就是说,这种方法创建一个属性对于每个TextBox并在单选按钮组选择更改时执行PropertyNotification。

问:
是否有可能以这样一种方式,视图模型只公开一个属性,而不是三个属性(ValueB1,ValueB2,ValueB3)做到这一点: 这个单一属性将返回一个ObservableCollection < >或IList(或类似的索引选择)?


我想到了一种可能的方式,这可能来完成: 在VM我们将不得不像

public ObservableCollection<float> ArraySlice 
    { 
     get 
     { 
      return new ObservableCollection<float>(_myModel.ArraySlice); 
     } 

    } 

在查看

<StackPanel Orientation="Horizontal"> 
<Label Content="B1" /> 
<TextBox Text="{Binding Path=WindSpeedAverage, Converter={StaticResource EnumToObservableCollectionConverter}, ConverterParameter={x:Static model:B.B1}}" /> 
</StackPanel> 

这EnumToObservableCollectionConverter – 一个这种方式很容易,它会把价值作为IList和简单的方式来施展虽然我实现了ConvertBack方法,但我只是简单地更新ObservableCollection而不更新模型类中的值本身。

这怎么办?有没有这种我缺少的共同模式


===========解决方案如下:

首先,我的道歉:我离开办公室前的最后一分钟回答。

所以,这里是我如何处理您的问题,但还有很多其他解决方案。按照你的意愿创建一个图形用户界面是最简单但最简单的方式(据我所知,正确)。

让我们从视图模型开始:您的案例看起来是一个简单的主 – 细节上下文,但它也可以被看作是一个分层上下文。

public class VM 
{ 
    public VM() 
    { 
     this._aItems = new ObservableCollection<VMA>(); 
    } 

    private ObservableCollection<VMA> _aItems; 

    public Collection<VMA> AItems 
    { 
     get { return this._aItems; } 
    } 
} 


public class VMA 
{ 
    public VMA() 
    { 
     this._bItems = new ObservableCollection<VMB>(); 
    } 

    public string Title { get; set; } 

    private ObservableCollection<VMB> _bItems; 

    public Collection<VMB> BItems 
    { 
     get { return this._bItems; } 
    } 
} 


public class VMB : INotifyPropertyChanged 
{ 
    public string Title { get; set; } 

    private string _value; 
    public string Value 
    { 
     get { return this._value; } 
     set 
     { 
      if (this._value != value) 
      { 
       this._value = value; 
       this.OnPropertyChanged("Value"); 
      } 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void OnPropertyChanged(string name) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged(
       this, 
       new PropertyChangedEventArgs(name) 
       ); 
     } 
    } 
} 

请注意,“值”属性的类型是“字符串”,尽管目标值应限制为浮点型。这是因为一个字符串总是被接受,你可以实现你自己的验证逻辑。相反,数字属性可能会导致异常,而输入的字符不允许作为数字。

以上的ViewModels在下列方式填充(如例如):

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

     var rnd = new Random(); 
     var vm = new VM(); 
     this.DataContext = vm; 

     //enum "A" 
     foreach (var a in Enum.GetNames(typeof(A))) 
     { 
      var vma = new VMA(); 
      vma.Title = a; 
      vm.AItems.Add(vma); 

      //enum "B" 
      foreach (var b in Enum.GetNames(typeof(B))) 
      { 
       var vmb = new VMB(); 
       vmb.Title = b; 
       vmb.Value = rnd.Next(1000).ToString(); 
       vma.BItems.Add(vmb); 
      } 
     } 
    } 
} 

请注意,我没有使用型号为简单起见,但你可以随时添加。相反,我选择填充随机整数。

最后,这里是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" 
     > 

    <Window.Resources> 

     <DataTemplate x:Key="tplA"> 
      <RadioButton 
       Content="{Binding Path=Title}" 
       IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ListBoxItem}}" 
       /> 
     </DataTemplate> 

     <DataTemplate x:Key="tplB"> 
      <StackPanel Orientation="Horizontal"> 
       <TextBlock Text="{Binding Path=Title}" Width="30" /> 
       <TextBox Text="{Binding Path=Value}" Width="100" /> 
      </StackPanel> 
     </DataTemplate> 

    </Window.Resources> 

    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition /> 
      <ColumnDefinition /> 
     </Grid.ColumnDefinitions> 

     <ListBox 
      ItemsSource="{Binding Path=AItems}" 
      ItemTemplate="{StaticResource tplA}" 
      Width="150" 
      Height="200" 
      Grid.Column="0" 
      x:Name="L1" 
      > 
     </ListBox> 

     <ListBox 
      ItemsSource="{Binding Path=SelectedItem.BItems, ElementName=L1}" 
      ItemTemplate="{StaticResource tplB}" 
      Width="150" 
      Height="200" 
      Grid.Column="1" 
      > 
     </ListBox> 
    </Grid> 
</Window> 

的视觉效果看起来像下面的图片。

enter image description here


版权声明:本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。
喜欢 (0)