我尝试从ViewModel中读取属性,该属性绑定到windows窗体上的一些控件。我使ViewModel作为单例,所以我确信只有一个实例。问题是,当我去其他类,并获得ViewModel的单例实例读取它的属性,他们不等于这些在ViewModel类。下面是ViewModel类:
class EditorToolboxViewModel : INotifyPropertyChanged
{
static EditorToolboxViewModel instance;
public static EditorToolboxViewModel GetSingleton()
{
if (instance == null)
instance = new EditorToolboxViewModel();
return instance;
}
public event PropertyChangedEventHandler PropertyChanged;
public int BrushRadius {get; set;}
public int BrushSensitivity {get; set;}
public bool TerrainUp { get; set; }
public bool TerrainDown { get; set; }
public bool AddTerrainSlot { get; set; }
public bool RemoveTerrainSlot { get; set; }
public bool FlattenTerrain { get; set; }
public float FlattenTerrainTarget { get; set; }
private EditorToolboxViewModel()
{
BrushRadius = 10;
BrushSensitivity = 1;
}
}
这是我如何将它绑定到windows窗体上的控件:
this.viewModel = EditorToolboxViewModel.GetSingleton();
this.trackBarBrushRadius.DataBindings.Add(new Binding("Value", viewModel, "BrushRadius"));
this.trackBarTerrainBrushSensitivity.DataBindings.Add(new Binding("Value", viewModel, "BrushSensitivity"));
this.radioButtonIncreaseHeight.DataBindings.Add("Checked", viewModel, "TerrainUp");
this.radioButtonDecreaseHeight.DataBindings.Add("Checked", viewModel, "TerrainDown");
this.radioButtonAddTerrainSlot.DataBindings.Add(new Binding("Checked", viewModel, "AddTerrainSlot"));
this.radioButtonRemoveTerrainSlot.DataBindings.Add(new Binding("Checked", viewModel, "RemoveTerrainSlot"));
this.radioButtonFlattenTerrain.DataBindings.Add(new Binding("Checked", viewModel, "FlattenTerrain"));
this.textBoxTerrainFlattenTarget.DataBindings.Add(new Binding("Text", viewModel, "FlattenTerrainTarget"));
现在,当我点击TerrainUp单选按钮并尝试从其他类的viewmodel读取值时,它仍然是false:
bool b = EditorToolboxViewModel.GetSingleton().TerrainUp;
在ViewModel类中,一切都是正确的,但是在其他地方访问它会导致数据不匹配。
任何想法?
1)通过a ==比较检查对象是否相同。由于绑定了一个窗口,属性可能在不同的时间具有不同的值。如果你确认对象是相同的,你就知道Singleton正在工作,并且可能有一个绑定改变了属性值。
2) Singleton应该有一个私有字段,而不是一个内部字段。
我最终解决了我的问题。
看起来这是一个已知的bug,单选按钮在状态改变期间失去绑定,所以这就是为什么视图模型行为不正确。看这里:http://www.abhisheksur.com/2011/03/issue-with-radiobuttons-and-binding-for.html
一个可能的解决方案是用复选框代替单选按钮。但是这样做时,请记住两件事:
- 在viewmodel中设置所有的复选框绑定为false,然后在它应该在的地方设置为true(如果你想让复选框表现得像单选按钮)。
重要: ViewModel不是在单击复选框时被验证,而是在复选框失去焦点时被验证。因此,要在单击后强制视图模型验证,只需通过编程将焦点更改为表单上的其他控件,如下所示:
void CheckBoxes_CheckedChanged(object sender, EventArgs e) { CheckBox c = (CheckBox)sender; var otherCheckBoxName = typeof(EditorToolbox).GetRuntimeFields().Where(x => x.FieldType == typeof(CheckBox) && !x.Name.Equals(c.Name)).Select(x => x.Name).FirstOrDefault(); CheckBox c2 = (CheckBox)this.Controls.Find(otherCheckBoxName, true).FirstOrDefault(); c2.Focus(); }