动态元素命令 Binding/INotifyPropertyChanged - TKCustomMap
Dynamic Element Command Binding/INotifyPropertyChanged - TKCustomMap
我正在使用 TK.CustomMap,但在执行我需要在视图中执行的方法时遇到问题。我想知道这可能是什么原因。起初我只是在代码中使用 MapClicked 方法,但现在我正在尝试使用 Bindable Command 属性,但我不知道它是否正在触发。 [编辑] 我无法在 XAML 中绑定此命令,因为这些元素都是在后面的代码中动态添加的。我确实相信这些命令实际上正在触发,也许 INotifyPropertyChanged
实施的问题更多,但我不确定 [编辑]
这里是 xaml.cs
绑定和 MapClicked 命令
mapView.SetBinding(TKCustomMap.MapClickedCommandProperty, "MapClickedCommand");
private void MapView_MapClicked(object sender, TKGenericEventArgs<TK.CustomMap.Position> e)
{
var map = sender as TKCustomMap;
if (map.MapClickedCommand != null)
{
map.MapClickedCommand.Execute(e);
}
}
在 ViewModel 中 MapClickedCommand
及其支持方法和对象
public Command<Position> MapClickedCommand
{
get
{
return new Command<Position>(async (position) =>
{
if (!ZoneOpen)
return;
ActiveZonePositions.Add(position);
if (ActiveZonePositions.Count > 1)
{
ZonePolyLine.LineCoordinates = ActiveZonePositions;
}
var pin = new TKCustomMapPin
{
Position = new TK.CustomMap.Position(position.Latitude, position.Longitude),
IsVisible = true,
IsDraggable = true,
ShowCallout = false,
};
_pins.Add(pin);
await CreatePointAsync(position);
PointCount++;
});
}
}
public async Task CreatePointAsync(TK.CustomMap.Position position)
{
var zone = await RetrieveZoneAsync(ActiveZoneID);
Model.Point PointToAdd = new Model.Point
{
ZoneSys = zone.ZoneSys,
PointName = "",
Latitude = position.Latitude,
Longitude = position.Longitude,
PointOrder = PointCount + 1
};
ActiveZonePoints.Add(PointToAdd);
}
public static List<Position> ActiveZonePositions = new List<Position>();
public static List<Model.Point> ActiveZonePoints = new List<Model.Point>();
public static int ActiveZoneID;
public static int ActivePointID;
public static int PointCount;
public static bool ZoneOpen = false;
public ObservableCollection<TKCustomMapPin> Pins
{
get { return _pins; }
set
{
if (_pins != value)
{
_pins = value;
OnPropertyChanged("Pins");
}
}
}
有一个 OpenNewZone() 方法将 ZoneOpen
设置为 true。
这里是 _pins
列表
的各种 属性 更改的侦听器等
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
ObservableCollection<TKCustomMapPin> _pins;
和 ViewModel 的方法
public MapPageViewModel()
{
_pins = new ObservableCollection<TKCustomMapPin>();
}
所以我认为,随着 属性 更改的侦听器,它应该在我单击它时立即向地图添加一个图钉,但事实并非如此。可能是我遗漏了一些关于绑定的内容,但我觉得我已经通读了所有文章和许多问题,并且涵盖了所有基础知识。
有人看到我遗漏了什么吗?
附录:
我也知道地图正在感应点击,因为我在 VS
的输出中看到了这一点
07-08 18:42:48.711 D/ViewRootImpl@af05362[MainActivity](30715): ViewPostIme pointer 0
07-08 18:42:48.787 D/ViewRootImpl@af05362[MainActivity](30715): ViewPostIme pointer 1
这不是设置命令绑定的正确方法。命令绑定一般用于xaml。对象公开 ICommand 类型的 属性,然后在 xaml 中将命令 属性 绑定到该 ICommand。
对象会像这样声明命令:
public class MyViewModel
{
public ICommand MyCommand {get;set;}
public MyViewModel()
{
MyCommand = new Command(Command_MyCommand);
}
public void Command_MyCommand(object paramter)
{
// do something nifty
}
}
在后面的代码中,将 BindingContext
设置为 MyViewModel
的实例。
然后在xaml中可以绑定命令属性到命令:
<Button Text="Press me!" Command="{Binding MyCommand}" />
要以编程方式设置命令,您只需分配:
SomeControl.Command = MyViewModelInstance.MyCommand;
如果您想在代码隐藏中进行,只需订阅该事件会更容易。
** 更新:在你的控制下,它看起来像这样:
mapView.CommandClickedCommand = new Command(Map_ClickedCommand);
public async void Map_ClickedCommand(object p1)
{
var position = p1 as Position; // not sure what the type of position is
if (!ZoneOpen)
return;
ActiveZonePositions.Add(position);
if (ActiveZonePositions.Count > 1)
{
ZonePolyLine.LineCoordinates = ActiveZonePositions;
}
var pin = new TKCustomMapPin
{
Position = new TK.CustomMap.Position(position.Latitude, position.Longitude),
IsVisible = true,
IsDraggable = true,
ShowCallout = false,
};
_pins.Add(pin);
await CreatePointAsync(position);
PointCount++;
};
想通了这一点。需要更改我用作命令的方法。我提到的 OpenNewZone
方法被绑定为一个命令。事实证明,命令可以毫无问题地以这种方式绑定。唯一的问题是 OpenNewZone
命令没有将 ZoneOpen
布尔值设置为 true,因为它没有触发。我把它设置为一种方法,但这样设置
public Command<EventArgs> OpenNewZone
{
get
{
return new Command<EventArgs>(async e =>
{
ZoneOpen = true;
PointCount = 0;
ActiveZonePositions.Clear();
Zone ZoneToAdd = new Zone
{
Contactsys = MobileUser.ContactSys,
ZoneTypesSys = 1,
OrganizationSys = MobileUser.OrganizationSys,
ZoneName = ""
};
ActiveZoneID = await AddZoneToDBAsync(ZoneToAdd);
ZoneToAdd.ID = ActiveZoneID;
ZoneToAdd.ZoneSys = ActiveZoneID;
await AddZoneToDBAsync(ZoneToAdd);
});
}
}
然后这样绑定
Binding openNewZone = new Binding("OpenNewZone");
addZoneButton.SetBinding(Button.CommandProperty, openNewZone);
addZoneButton.Clicked += AddZoneButton_Clicked;
然后像这样的点击事件处理程序
private void AddZoneButton_Clicked(object sender, EventArgs e)
{
var button = sender as Button;
MapField.Children.Remove(button);
if (button.Command != null)
{
button.Command.Execute(e);
}
zoneControls.Orientation = StackOrientation.Horizontal;
zoneControls.VerticalOptions = LayoutOptions.End;
zoneControls.HorizontalOptions = LayoutOptions.FillAndExpand;
zoneControls.HeightRequest = 35;
MapField.Children.Add(zoneControls);
zoneControls.Children.Add(saveZoneButton);
zoneControls.Children.Add(setZonePropsButton);
zoneControls.Children.Add(deleteZoneButton);
zoneControls.Children.Add(closeControlsButton);
}
每次都完美无缺。所以我原来的问题中的一切实际上都是正确的!!卫生署!
但这很棒,因为现在我知道如何在动态添加的元素上完美地编写和绑定命令,同时仍然保持 MVVM 结构。
TK.CustomMap nuget 有自己的绑定属性,因此它们的设置略有不同,但现在一切正常:)
我正在使用 TK.CustomMap,但在执行我需要在视图中执行的方法时遇到问题。我想知道这可能是什么原因。起初我只是在代码中使用 MapClicked 方法,但现在我正在尝试使用 Bindable Command 属性,但我不知道它是否正在触发。 [编辑] 我无法在 XAML 中绑定此命令,因为这些元素都是在后面的代码中动态添加的。我确实相信这些命令实际上正在触发,也许 INotifyPropertyChanged
实施的问题更多,但我不确定 [编辑]
这里是 xaml.cs
绑定和 MapClicked 命令
mapView.SetBinding(TKCustomMap.MapClickedCommandProperty, "MapClickedCommand");
private void MapView_MapClicked(object sender, TKGenericEventArgs<TK.CustomMap.Position> e)
{
var map = sender as TKCustomMap;
if (map.MapClickedCommand != null)
{
map.MapClickedCommand.Execute(e);
}
}
在 ViewModel 中 MapClickedCommand
及其支持方法和对象
public Command<Position> MapClickedCommand
{
get
{
return new Command<Position>(async (position) =>
{
if (!ZoneOpen)
return;
ActiveZonePositions.Add(position);
if (ActiveZonePositions.Count > 1)
{
ZonePolyLine.LineCoordinates = ActiveZonePositions;
}
var pin = new TKCustomMapPin
{
Position = new TK.CustomMap.Position(position.Latitude, position.Longitude),
IsVisible = true,
IsDraggable = true,
ShowCallout = false,
};
_pins.Add(pin);
await CreatePointAsync(position);
PointCount++;
});
}
}
public async Task CreatePointAsync(TK.CustomMap.Position position)
{
var zone = await RetrieveZoneAsync(ActiveZoneID);
Model.Point PointToAdd = new Model.Point
{
ZoneSys = zone.ZoneSys,
PointName = "",
Latitude = position.Latitude,
Longitude = position.Longitude,
PointOrder = PointCount + 1
};
ActiveZonePoints.Add(PointToAdd);
}
public static List<Position> ActiveZonePositions = new List<Position>();
public static List<Model.Point> ActiveZonePoints = new List<Model.Point>();
public static int ActiveZoneID;
public static int ActivePointID;
public static int PointCount;
public static bool ZoneOpen = false;
public ObservableCollection<TKCustomMapPin> Pins
{
get { return _pins; }
set
{
if (_pins != value)
{
_pins = value;
OnPropertyChanged("Pins");
}
}
}
有一个 OpenNewZone() 方法将 ZoneOpen
设置为 true。
这里是 _pins
列表
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
ObservableCollection<TKCustomMapPin> _pins;
和 ViewModel 的方法
public MapPageViewModel()
{
_pins = new ObservableCollection<TKCustomMapPin>();
}
所以我认为,随着 属性 更改的侦听器,它应该在我单击它时立即向地图添加一个图钉,但事实并非如此。可能是我遗漏了一些关于绑定的内容,但我觉得我已经通读了所有文章和许多问题,并且涵盖了所有基础知识。
有人看到我遗漏了什么吗?
附录: 我也知道地图正在感应点击,因为我在 VS
的输出中看到了这一点07-08 18:42:48.711 D/ViewRootImpl@af05362[MainActivity](30715): ViewPostIme pointer 0
07-08 18:42:48.787 D/ViewRootImpl@af05362[MainActivity](30715): ViewPostIme pointer 1
这不是设置命令绑定的正确方法。命令绑定一般用于xaml。对象公开 ICommand 类型的 属性,然后在 xaml 中将命令 属性 绑定到该 ICommand。
对象会像这样声明命令:
public class MyViewModel
{
public ICommand MyCommand {get;set;}
public MyViewModel()
{
MyCommand = new Command(Command_MyCommand);
}
public void Command_MyCommand(object paramter)
{
// do something nifty
}
}
在后面的代码中,将 BindingContext
设置为 MyViewModel
的实例。
然后在xaml中可以绑定命令属性到命令:
<Button Text="Press me!" Command="{Binding MyCommand}" />
要以编程方式设置命令,您只需分配:
SomeControl.Command = MyViewModelInstance.MyCommand;
如果您想在代码隐藏中进行,只需订阅该事件会更容易。
** 更新:在你的控制下,它看起来像这样:
mapView.CommandClickedCommand = new Command(Map_ClickedCommand);
public async void Map_ClickedCommand(object p1)
{
var position = p1 as Position; // not sure what the type of position is
if (!ZoneOpen)
return;
ActiveZonePositions.Add(position);
if (ActiveZonePositions.Count > 1)
{
ZonePolyLine.LineCoordinates = ActiveZonePositions;
}
var pin = new TKCustomMapPin
{
Position = new TK.CustomMap.Position(position.Latitude, position.Longitude),
IsVisible = true,
IsDraggable = true,
ShowCallout = false,
};
_pins.Add(pin);
await CreatePointAsync(position);
PointCount++;
};
想通了这一点。需要更改我用作命令的方法。我提到的 OpenNewZone
方法被绑定为一个命令。事实证明,命令可以毫无问题地以这种方式绑定。唯一的问题是 OpenNewZone
命令没有将 ZoneOpen
布尔值设置为 true,因为它没有触发。我把它设置为一种方法,但这样设置
public Command<EventArgs> OpenNewZone
{
get
{
return new Command<EventArgs>(async e =>
{
ZoneOpen = true;
PointCount = 0;
ActiveZonePositions.Clear();
Zone ZoneToAdd = new Zone
{
Contactsys = MobileUser.ContactSys,
ZoneTypesSys = 1,
OrganizationSys = MobileUser.OrganizationSys,
ZoneName = ""
};
ActiveZoneID = await AddZoneToDBAsync(ZoneToAdd);
ZoneToAdd.ID = ActiveZoneID;
ZoneToAdd.ZoneSys = ActiveZoneID;
await AddZoneToDBAsync(ZoneToAdd);
});
}
}
然后这样绑定
Binding openNewZone = new Binding("OpenNewZone");
addZoneButton.SetBinding(Button.CommandProperty, openNewZone);
addZoneButton.Clicked += AddZoneButton_Clicked;
然后像这样的点击事件处理程序
private void AddZoneButton_Clicked(object sender, EventArgs e)
{
var button = sender as Button;
MapField.Children.Remove(button);
if (button.Command != null)
{
button.Command.Execute(e);
}
zoneControls.Orientation = StackOrientation.Horizontal;
zoneControls.VerticalOptions = LayoutOptions.End;
zoneControls.HorizontalOptions = LayoutOptions.FillAndExpand;
zoneControls.HeightRequest = 35;
MapField.Children.Add(zoneControls);
zoneControls.Children.Add(saveZoneButton);
zoneControls.Children.Add(setZonePropsButton);
zoneControls.Children.Add(deleteZoneButton);
zoneControls.Children.Add(closeControlsButton);
}
每次都完美无缺。所以我原来的问题中的一切实际上都是正确的!!卫生署!
但这很棒,因为现在我知道如何在动态添加的元素上完美地编写和绑定命令,同时仍然保持 MVVM 结构。
TK.CustomMap nuget 有自己的绑定属性,因此它们的设置略有不同,但现在一切正常:)