我认为我在UWP应用程序中遇到了线程问题。 我想做一个非常简单的事情:UWP:在设置另一个属性后设置属性时的异常
- 一个带2个数字字段的UI;
- 如果在
field1
中键入数字值,我希望field2
设置为field1
(例如:field2 = ratio * field1
)的比率。
我正在使用x:Bind
和TextChanging
事件。由于不明原因,我无法在XAML中“调用”TextChanging
事件,而无需在启动时发生异常。因此,我正在使用Loaded
事件。
这里是我的模型类,简称MyModel
:
public class MyModel : INotifyPropertyChanged
{
private readonly uint r1 = 3;
private uint _field1;
public uint Field1
{
get { return this._field1; }
set
{
this.Set(ref this._field1, value);
if (value == 0)
{
Field2 = 0;
}
else
{
Field2 = value * r1;
}
}
}
private uint _field2;
public uint Field2
{
get { return this._field2; }
set
{
this.Set(ref this._field2, value);
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisedPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
{
if (Equals(storage, value))
{
return false;
}
else
{
storage = value;
this.RaisedPropertyChanged(propertyName);
return true;
}
}
}
我的视图模型:
public class MyModelViewModel : INotifyPropertyChanged
{
public MyModel MyModel { get; set; }
public MyModelViewModel()
{
// Initialisation de notre page
this.MyModel = new MyModel()
{
Field1 = 0
};
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
我后面的代码(我过滤输入,以避免铸造除外):
public sealed partial class MainPage : Page
{
public MyModelViewModel ViewModel { get; set; } = new MyModelViewModel();
public MainPage()
{
this.InitializeComponent();
}
private void InitField1(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
field1.TextChanging += field1_TextChanging;
}
private void InitField2(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
field2.TextChanging += field2_TextChanging;
}
private void field1_TextChanging(TextBox sender, TextBoxTextChangingEventArgs args)
{
var error = errorTextBlock;
error.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
Regex regex = new Regex("[^0-9]+"); // All but numeric
if (regex.IsMatch(sender.Text))
{
error.Text = "Non numeric char";
error.Visibility = Windows.UI.Xaml.Visibility.Visible;
sender.Text = this.ViewModel.MyModel.Field1.ToString();
}
else
{
this.ViewModel.MyModel.Field1 = Convert.ToUInt32(sender.Text);
}
}
private void field2_TextChanging(TextBox sender, TextBoxTextChangingEventArgs args)
{
var error = errorTextBlock;
error.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
Regex regex = new Regex("[^0-9]+");
if (regex.IsMatch(sender.Text))
{
error.Text = "Non numeric char";
error.Visibility = Windows.UI.Xaml.Visibility.Visible;
sender.Text = this.ViewModel.MyModel.Field2.ToString();
}
else
{
this.ViewModel.MyModel.Field2 = Convert.ToUInt32(sender.Text);
}
}
}
最后,我的XAML:
<TextBlock Grid.Row="0" Grid.Column="0" x:Name="errorTextBlock" Text="" Visibility="Collapsed" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Field 1" />
<TextBox Grid.Row="1" Grid.Column="1" x:Name="field1" Text="{x:Bind ViewModel.MyModel.Field1, Mode=OneWay}" Loaded="InitField1" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Field 2" />
<TextBox Grid.Row="2" Grid.Column="1" x:Name="field2" Text="{x:Bind ViewModel.MyModel.Field2, Mode=OneWay}" Loaded="InitField2" />
在运行时,如果我输入field1
非数字字符,输入过滤,field1
返回先前没有屏幕“闪烁”的值(这就是为什么我使用TextChanging
事件,而不是TextChanged
)。完善!但是,如果我输入数字字符,field1
正确更新(我可以看到,断点),但是当field2
设置,我当RaisedPropertyChanged
被称为本地异常:
我怀疑某种线程错误,但我对这种开发很新颖。任何想法?谢谢!
感谢您的详细回复;如果它不打扰你,我会一步一步来:我尝试了“经典”的“绑定”,它工作得很好。对于'x:Bind',我明白你在ViewModel中做了什么,但这意味着我的模型“已经消失”了?是否可以将'Value1'和'Value2'放入模型中并使其以同样的方式工作?对我来说,这是我的模型,它说:“嗨,Value2必须始终是Value1 * 3”,所以看到ViewModel中的逻辑有点混乱。我清楚了吗? – benichka
@benichka根据需要更新以分离出Model类。 –
感谢您提供更多详情,我会尽力而为。不过,我仍然有点困惑,在我的模型中,我的字段是“字符串”而不是“int”。我可能还没有很好地理解MVVM,但我认为模型必须独立于视图之外?在这种情况下,情况并非如此(我们正在处理'string'而不是'int'来防止'argumentException')。我问了另一个问题来解决这个问题。显然唯一的选择是使用转换器。 – benichka