我認爲我在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