从模型更新动态创建的复选框状态的最佳做法是什么?复选框的实际值保存在主模型的子模型中,并根据其逻辑进行更改。复选框的属性绑定到其各自的FooViewModel。但是如何更改FooViewModel的属性呢?
1种方式:主模型触发特殊事件 - >主VM处理它并找到目标FooViewModel使用事件args更新 - >主VM使用事件args中指定的值设置目标FooViewModel属性 - >复选框通过绑定到FooViewModel
更新2路:主模型包含实现INPC的FooModel的可观察集合,每个都用FooViewModel包装(使用主VM中的CollectionChanged事件)。主模型设置了一些FooModel的属性 - > FooViewModel处理PropertyChanged并进一步传输它自己的PropertyChanged事件 - >复选框通过绑定更新到FooViewModel。 FooViewModel中的转移代码:
this._model.PropertyChanged += (s, a) => this.RaisePropertyChangedEvent(a.PropertyName);
我的第二种方式的实施是下一步:
// MainModel class that holds collection of extra models (CfgActionModel):
class MainModel: BindableBase
{
ObservableCollection<CfgActionModel> _actionsColl
= new ObservableCollection<CfgActionModel>();
public ObservableCollection<CfgActionModel> ActionCollection
{
get => this._actionsColl;
}
public void AddAction(ConfigEntry cfgEntry, bool isMeta)
{
CfgActionModel actionModel = new CfgActionModel()
{
CfgEntry = cfgEntry,
Content = cfgEntry.ToString(),
IsEnabled = true,
IsChecked = false
};
this._actionsColl.Add(actionModel);
}
}
// Extra model that is wrapped with CfgActionViewModel:
class CfgActionModel: BindableBase
{
ConfigEntry _cfgEntry; // Custom enumeration value unique for each checkbox
string _content;
bool _isEnabled = false;
bool _isChecked = false;
public ConfigEntry CfgEntry
{
get => this._cfgEntry;
set
{
if (this._cfgEntry == value) return;
this._cfgEntry = value;
this.RaisePropertyChangedEvent(nameof(CfgEntry));
}
}
public string Content
{
get => this._content;
set
{
if (this._content == value) return;
this._content = value;
this.RaisePropertyChangedEvent(nameof(Content));
}
}
public bool IsEnabled
{
get => this._isEnabled;
set
{
if (this._isEnabled == value) return;
this._isEnabled = value;
this.RaisePropertyChangedEvent(nameof(IsEnabled));
}
}
public bool IsChecked
{
get => this._isChecked;
set
{
if (this._isChecked == value) return;
this._isChecked = value;
this.RaisePropertyChangedEvent(nameof(IsChecked));
}
}
}
// CfgActionViewModel that is checkbox in UI is bound to:
class CfgActionViewModel: BindableBase
{
CfgActionModel _model;
public CfgActionViewModel(CfgActionModel model)
{
this._model = model;
this._model.PropertyChanged += (s, a) => this.RaisePropertyChangedEvent(a.PropertyName);
}
public string Content
{
get => this._model.Content;
set => this._model.Content = value;
}
public bool IsEnabled
{
get => this._model.IsEnabled;
set => this._model.IsEnabled = value;
}
public bool IsChecked
{
get => this._model.IsChecked;
set => this._model.IsChecked = value;
}
}
// MainViewModel where we fill the model with data:
class MainViewModel
{
MainModel model;
readonly ObservableCollection<CfgActionViewModel> _actionVMColl = new ObservableCollection<CfgActionViewModel>();
public ObservableCollection<CfgActionViewModel> ActionVMCollection => this._actionVMColl;
public MainViewModel()
{
this.model = new MainModel();
this.model.ActionCollection.CollectionChanged += (s, a) =>
{
// when new model is created we create new ViewModel wrapping it
if (a.Action == NotifyCollectionChangedAction.Add)
{
CfgActionModel newModel = (CfgActionModel) a.NewItems[0];
CfgActionViewModel actionViewModel = new CfgActionViewModel(newModel);
_actionVMColl.Add(actionViewModel);
}
};
model.AddAction(ConfigEntry.AutoBuy, false);
model.AddAction(ConfigEntry.Bomb, false);
}
}
View中的DataTemplate看起来像这样:
<DataTemplate DataType="{x:Type mvvm:CfgActionViewModel}">
<CheckBox
IsChecked="{Binding Path=IsChecked, Mode=TwoWay}"
IsEnabled="{Binding Path=IsEnabled, Mode=TwoWay}"
Content="{Binding Path=Content, Mode=OneWay}"/>
</DataTemplate>
MVVM是否可以避免在某处(第二路)避免与MainViewModel交互,或者每个subViewModel的属性必须由MainViewModel(第一路)设置?
答案 0 :(得分:0)
这两种方法都是可以接受的。但就个人而言,我会采用#1来保持我的模型尽可能薄。
您可以参考示例代码,了解如何进行#1。
[HttpPut("UpdateControlLinePointSet")]
public async Task<IActionResult> UpdateControlLinePointSet([FromBody] JArray pointSetJson)
{
if (!ModelState.IsValid) return BadRequest(ModelState);
foreach (JToken p in pointSetJson)
{
ControlLinePoint clp = _context.ControlLinePoint.First(x => x.ControlLinePointId == (int)p["ControlLinePointId"]);
JsonConvert.PopulateObject(p.ToString(), clp);
_context.Entry(clp).State = EntityState.Modified;
}
await _context.SaveChangesAsync();
return NoContent();
}
正如您所看到的,我甚至不需要在示例代码中包含任何模型,这意味着此处的所有逻辑都清楚地是表示层的一部分。 现在,您可以专注于模型中的业务/域逻辑。