[通过更改组合框单位更新文本框值

问题描述 投票:0回答:2

我想为我的Xamarin和Wpf项目提供一个转换器系统。我不想在数据库中保存任何单位,因此我想在用户更改单位时直接转换文本框值。

enter image description here

我公开了一些类似的可观察的收藏;

 public class AreaList : ObservableCollection<Unit>
    {
        public AreaList() : base()
        {
            Add(new Unit("mm²"));
            Add(new Unit("cm²"));
            Add(new Unit("dm²"));
            Add(new Unit("m²"));
        }
    }

 public class Unit
    {
        private string name;

        public Unit(string name)
        {
            this.name = name;
        }

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
    }

在视图中,我将集合绑定到我的组合框。我给我的TextBox他绑定属性的名称(Text =“ {Binding TxtBoxValue}” => x:Name =“ TxtBoxValue”)。 ConvertUnitValueCommand在视图模型中将此名称设置为字符串,以了解在更改单位时转换器函数应使用哪个变量。

查看

<UserControl.Resources>
        <c:AreaList x:Key="AreaListData" />
</UserControl.Resources>

<TextBox x:Name="TxtBoxValue"
         Text="{Binding Mode=TwoWay, Path=TxtBoxValue, UpdateSourceTrigger=PropertyChanged}">
</TextBox>

<ComboBox IsSynchronizedWithCurrentItem="True"
          IsEditable="False"
          DisplayMemberPath="Name"
          SelectedItem="{Binding Unit,Mode=OneWayToSource}"
          ItemsSource="{Binding Source={StaticResource AreaListData}}">
<i:Interaction.Triggers>
   <i:EventTrigger EventName="PreviewMouseLeftButtonDown">
         <i:InvokeCommandAction Command="{Binding ConvertUnitValueCommand}"
                                CommandParameter="{Binding ElementName=TxtBoxValue, Path=Name}" />
   </i:EventTrigger>
</i:Interaction.Triggers> 
</ComboBox>

ViewModel

private string ConvertControlName;

private void ConvertUnitValue(object obj)
{
    ConvertControlName = obj.ToString();
}

public Unit Unit
{
get => Get<Unit>();
set
{
     if (ConvertControlName != null)
     {
    FieldInfo variable = this.GetType().GetField(ConvertControlName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic);

    //Get the Value from setted Binding Variable
    double oldValue = (double)variable.GetValue(this);

    //Convert the value
    if (oldValue > 0)
    {
         double newValue = Converts.ConvertUnitValue(Unit, value, oldValue);
         variable.SetValue(this, newValue);
    }

    Set(value);
    }
}

也许任何人都可以给我一些启发来做得更好。

c# wpf xamarin mvvm converters
2个回答
0
投票

我对您的代码影响了解不多,但是我建议您尝试使用MVVM模式进行以下设计,该模式可以消除UI和后端之间的紧密耦合。我在这里把东西分开了

您的XAML将具有类似的代码

    <TextBox x:Name="unitTextbox"
     Text="{Binding Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    </TextBox>

    <ComboBox IsSynchronizedWithCurrentItem="True"
      IsEditable="False"
      DisplayMemberPath="Name"
      SelectedItem="{Binding SelectedUnit}"
      ItemsSource="{Binding AvailableUnits}">
    </ComboBox>

您的ViewModel将像

public class MainVm : Observable
{
    #region Private Fields
    private double _value;
    private ObservableCollection<Unit> _availableUnits;
    private Unit _selectedUnit;
    private Unit _previouslySelected;

    #endregion Private Fields

    #region Public Constructors

    public MainVm()
    {
        _availableUnits = new ObservableCollection<Unit>()
        {
          new Unit("mm²"),
          new Unit("cm²"),
          new Unit("dm²"),
          new Unit("m²")
        };
    }

    #endregion Public Constructors

    #region Public Properties

    public double Value
    {
        get
        {
            return _value;
        }
        set
        {
            if (_value != value)
            {
                _value = value;
                OnPropertyChanged();
            }
        }
    }

    public Unit SelectedUnit
    {
        get { return _selectedUnit; }
        set
        {

           _previouslySelected = _selectedUnit;
           _selectedUnit = value;
          // call to value conversion function
          // convert cm² to mm² or anything
           Value = UnitConvertor.Convert(_value, _previouslySelected.Name, _selectedUnit.Name);
           OnPropertyChanged();
        }
    }

    public ObservableCollection<Unit> AvailableUnits => _availableUnits;

    #endregion Public Properties
}

我的可观察班将是

 public class Observable : INotifyPropertyChanged
{
    #region Public Events

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion Public Events

    #region Protected Methods

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion Protected Methods
}

最好将枚举用于单位


0
投票

以下示例对基本单元的用户输入进行标准化:

Unit.cs

public class Unit
{
  public Unit(string name, decimal baseFactor)
  {
    this.Name = name;
    this.BaseFactor = baseFactor;
  }

  #region Overrides of Object

  /// <inheritdoc />
  public override string ToString() => this.Name;

  #endregion

  public string Name { get; set; }
  public decimal BaseFactor { get; set; }
}

ViewModel.cs

public class ViewModel : INotifyPropertyChanged
{
  public ViewModel()
  {
    this.Units = new List<Unit>()
    {
      new Unit("mm²", (decimal) (1 / Math.Pow(1000, 2))),
      new Unit("cm²", (decimal) (1 / Math.Pow(100, 2))),
      new Unit("dm²", (decimal) (1 / Math.Pow(10, 2))),
      new Unit("m²", 1)
    };
  }

  private void NormalizeValue()
  {
    this.NormalizedValue = this.UnitValue * this.SelectedUnit.BaseFactor;
  }

  private List<Unit> units;
  public List<Unit> Units
  {
    get => this.units;
    set
    {
      this.units = value;
      OnPropertyChanged();
    }
  }

  private Unit selectedUnit;
  public Unit SelectedUnit
  {
    get => this.selectedUnit;
    set
    {
      this.selectedUnit = value;
      OnPropertyChanged();

      NormalizeValue();
    }
  }

  private decimal unitValue;
  public decimal UnitValue
  {
    get => this.unitValue;
    set
    {
      this.unitValue = value;
      OnPropertyChanged();

      NormalizeValue();
    }
  }

  private decimal normalizedValue;
  public decimal NormalizedValue
  {
    get => this.normalizedValue;
    set
    {
      this.normalizedValue = value;
      OnPropertyChanged();
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;
  protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
  {
    this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  }
}

ManiWindow.xaml

<Window>
  <Window.DataContext>
    <ViewModel />
  </Window.DatContext>

  <StackPanel>

    <!-- Input -->
    <TextBox Text="{Binding UnitValue}"/>
    <ComboBox ItemsSource="{Binding Units}" 
              SelectedItem="{Binding SelectedUnit}"/>

    <TextBlock Text="{Binding NormalizedValue}"/>
  </StackPanel>
</Window>

0
投票

以下示例对基本单元的用户输入进行标准化:

ViewModel.cs

public class ViewModel : INotifyPropertyChanged
{
  private void NormalizeValue()
  {
    this.NormalizedValue = this.UnitValue * this.SelectedUnit.BaseFactor;
  }

  private List<Unit> units;
  public List<Unit> Units
  {
    get => this.units;
    set
    {
      this.units = value;
      OnPropertyChanged();
    }
  }

  private Unit selectedUnit;
  public Unit SelectedUnit
  {
    get => this.selectedUnit;
    set
    {
      this.selectedUnit = value;
      OnPropertyChanged();

      NormalizeValue();
    }
  }

  private decimal unitValue;
  public decimal UnitValue
  {
    get => this.unitValue;
    set
    {
      this.unitValue = value;
      OnPropertyChanged();

      NormalizeValue();
    }
  }

  private decimal normalizedValue;
  public decimal NormalizedValue
  {
    get => this.normalizedValue;
    set
    {
      this.normalizedValue = value;
      OnPropertyChanged();
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;
  protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
  {
    this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  }
}

ManiWindow.xaml

<Window>
  <Window.DataContext>
    <ViewModel />
  </Window.DatContext>

  <StackPanel>

    <!-- Input -->
    <TextBox Text="{Binding UnitValue}"/>
    <ComboBox ItemsSource="{Binding Units}" 
              SelectedItem="{Binding SelectedUnit}"/>

    <TextBlock Text="{Binding NormalizedValue}"/>
  </StackPanel>
</Window>
© www.soinside.com 2019 - 2024. All rights reserved.