创建一个新的控件怎么样?比如说BindableMap,它继承自 Map 并执行原始Map 内部缺乏的绑定更新。实现非常简单,我已经包含了 2 个基本需求; Pins 属性和当前 MapSpan。显然,您可以在此控件中添加自己的特殊需求。之后您所要做的就是将 ObservableCollection<Pin> 类型的属性添加到您的 ViewModel 并将其绑定到 XAML 中 BindableMap 的 PinsSource 属性。
这是 BindableMap:
public class BindableMap : Map
{
public BindableMap()
{
PinsSource = new ObservableCollection<Pin>();
PinsSource.CollectionChanged += PinsSourceOnCollectionChanged;
}
public ObservableCollection<Pin> PinsSource
{
get { return (ObservableCollection<Pin>)GetValue(PinsSourceProperty); }
set { SetValue(PinsSourceProperty, value); }
}
public static readonly BindableProperty PinsSourceProperty = BindableProperty.Create(
propertyName: "PinsSource",
returnType: typeof(ObservableCollection<Pin>),
declaringType: typeof(BindableMap),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
validateValue: null,
propertyChanged: PinsSourcePropertyChanged);
public MapSpan MapSpan
{
get { return (MapSpan)GetValue(MapSpanProperty); }
set { SetValue(MapSpanProperty, value); }
}
public static readonly BindableProperty MapSpanProperty = BindableProperty.Create(
propertyName: "MapSpan",
returnType: typeof(MapSpan),
declaringType: typeof(BindableMap),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
validateValue: null,
propertyChanged: MapSpanPropertyChanged);
private static void MapSpanPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var thisInstance = bindable as BindableMap;
var newMapSpan = newValue as MapSpan;
thisInstance?.MoveToRegion(newMapSpan);
}
private static void PinsSourcePropertyChanged(BindableObject bindable, object oldvalue, object newValue)
{
var thisInstance = bindable as BindableMap;
var newPinsSource = newValue as ObservableCollection<Pin>;
if (thisInstance == null ||
newPinsSource == null)
return;
UpdatePinsSource(thisInstance, newPinsSource);
}
private void PinsSourceOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UpdatePinsSource(this, sender as IEnumerable<Pin>);
}
private static void UpdatePinsSource(Map bindableMap, IEnumerable<Pin> newSource)
{
bindableMap.Pins.Clear();
foreach (var pin in newSource)
bindableMap.Pins.Add(pin);
}
}
注意事项:
- 为简单起见,我省略了 using 语句和命名空间声明。
- 为了在我们将成员添加到可绑定的
PinsSource 属性时更新我们的原始Pins 属性,我将PinsSource 声明为ObservableCollection<Pin> 并订阅了它的CollectionChanged 事件。显然,如果您打算只更改绑定属性的整个值,则可以将其定义为 IList。
关于这个问题的 2 个第一个答案,我的最后一句话:
虽然将 View 控件作为 ViewModel 属性可以让我们免于在代码中编写业务逻辑,但它仍然感觉有点 hacky。在我看来,MVVM 的 VM 部分(嗯,至少是关键点)的全部意义在于它与 V 完全分离并解耦。而上述答案中提供的解决方案实际上是这样的:
将 View Control 插入 ViewModel 的核心。
我认为这样,不仅你打破了 MVVM 模式,而且你也伤了它的心!