Did anyone experience the following issue?
The pin is nowhere to be found. there are very few samples out there and I can't find one that helps me resolve this issue.
Literally, I copied and pasted the snippet from the project sample from TK.CustomMap github
Image with working pin from the original project
Now, on mine, same snippet. code below
The pin is working because it clearly shows all the properties I added to it, such as the title. I know this by debugging. but is not getting into the view. so I believe. I have issues with the binding.
ViewModel
/// <summary>
/// Pins bound to the <see cref="TKCustomMap"/>
/// </summary>
public ObservableCollection<TKCustomMapPin> Pins
{
get { return _pins; }
set
{
if (_pins != value)
{
_pins = value;
OnPropertyChanged("Pins");
}
}
}
MapSpan _mapRegion = MapSpan.FromCenterAndRadius(new Position(37.787332, -122.410540), Distance.FromKilometers(2));
Position _mapCenter;
ObservableCollection<TKCustomMapPin> _pins;
constructor
_mapCenter = new Position(37.787332, -122.410540);
_pins = new ObservableCollection<TKCustomMapPin>();
CenterMap();
void CenterMap()
{
var stopOne = new Position(26.0769102268052, -80.2535091197863);
var pin = new TKCustomMapPin
{
Position = stopOne,
ShowCallout = true,
IsDraggable = true,
DefaultPinColor = Color.GreenYellow
};
_pins.Add(pin);
}
XAML
<tk:TKCustomMap
x:Name="mapView"
IsRegionChangeAnimated ="true"
HasZoomEnabled="True"
MapType="Satellite"
WidthRequest="500"
HeightRequest="800"
IsShowingUser="true"
IsClusteringEnabled="true"
MapRegion="{Binding MapRegion}"
Polygons="{Binding Polygons}"
CalloutClickedCommand ="{Binding CalloutClickedCommand}"
Routes="{Binding Routes}"
Pins="{Binding Pins}"/>
Related
I'm trying to use certain icon instead of default Xamarin.Forms pins on Map.
So I created CustomisePin class that inheritance Pin.
using Xamarin.Forms.Maps;
namespace agroNet.Tools
{
public class CustomPin : Pin
{
public string PinIcon { get; set; }
}
}
Here is what I tried in my ViewModel
private Map _map;
public IrrigNetViewModel(Map map)
{
dialog = UserDialogs.Instance.Loading(AppResource.LocalizationResource.Loading);
TabTappedCommand = new Command((tabName) => OnTapClicked(tabName.ToString()));
HideListOnTapCommand = new Command(HideListOnTap);
_map = map;
GetData();
}
And here is method wor set pins on positions.
public void LoadMapTab()
{
//var irrigNetPins = new List<CustomPin>();
foreach (var item in IrrigNetCollection)
{
//var pins = new CustomPin
//{
// Label = item.StationName,
// Position = new Position(item.StationLatitude, item.StationLongitude),
// PinIcon = "satellite.png"
//};
_map.Pins.Add(new CustomPin
{
Label = item.StationName,
Position = new Position(item.StationLatitude, item.StationLongitude),
//PinIcon = P
});
_map.MoveToRegion(
MapSpan.FromCenterAndRadius(new Position(item.StationLatitude, item.StationLongitude),
Distance.FromKilometers(30)));
//irrigNetPins.Add(pins);
}
//return irrigNetPins;
}
In LoadMapTab under the comment lines is what I have tried to set pin icon.
And here is part of View if it's important because of Binding Context.
public partial class IrrigNetPage : ContentPage
{
public IrrigNetPage()
{
InitializeComponent();
BindingContext = new IrrigNetViewModel(MainMap);
}
}
I find some examples on Google, like:
https://github.com/raechten/BindableMapTest
https://github.com/paulpatarinski/ShouldIWashMyCar
For some reason I can't event run them, but still I tried to use code and no matter what I have Pin are alwas default, or not even show.
What is simple way to set certain icon for pin and is it posiple to render it just with some path to the icon without rendering map also (Because I saw many create costumise map for customised pins).
Also If it's important for someon I'm using MVVM patern.
The official Xamarin sample and documentation is outdated. I modified the official Custom Pin sample in order to use custom pins in iOS and Android. The project is hosted on GitHub.
An issue is reported about the official sample over here.
I have Areas tab which contain grid with some calculations.
That calculations depends from area which is selected.
Situation is next: One object can have several areas, and when I open Areas tab, it calculates good but, when in object I change Area from one to another, value in calculations stays from previous. On the other words: it not get updated. I am using this code:
[Control("TabPage")]
class TabLineAreaGroup
{
public void pageActivated()
{
PMCContractArea contractArea;
AmountMST sumContractArea;
super();
pmcContractLine_ds.readCommonAreas(pmcContractLine);
h1_h2.realValue(pmcContractLine_ds.h1_h2(pmcContractLine));
efa.realValue(pmcContractLine_ds.efa(pmcContractLine));
bfa.realValue(pmcContractLine_ds.bfa(pmcContractLine));
mfa.realValue(pmcContractLine_ds.mfa(pmcContractLine));
sumArea.realValue(h1_h2.realValue() + efa.realValue() + bfa.realValue() + mfa.realValue());
while select AreaSelector, sum(RentalValue)
from contractArea
group by AreaSelector
where contractArea.ContractId == pmcContract.ContractId
&& contractArea.RentalObjectId == pmcContractLine.RentalObjectId
{
sumContractArea += contractArea.RentalValue;
switch (contractArea.AreaSelector)
{
case PMEAreaSelector::CommonAreaBuilding :
contractAreaBFA.realValue(contractArea.RentalValue);
break;
case PMEAreaSelector::CommonAreaSection :
contractAreaEFA.realValue(contractArea.RentalValue);
break;
case PMEAreaSelector::PrimaryArea, PMEAreaSelector::SecondaryArea :
contractAreaH1_H2.realValue(contractArea.RentalValue);
break;
case PMEAreaSelector::CommonAreaFixed :
contractAreaMFA.realValue(contractArea.RentalValue);
break;
}
}
contractAreaSum.realValue(sumContractArea);
}
}
What I need to add in this code, so when area is changed to update the calculations in grid ?
For Dynamics 365, Microsoft sometimes deprecates methods and doesn't update documentation, or they leave methods available, but have not implemented them.
For D365, it's likely you will need to use the event handler method on the Tab control.
Below is a sample where I just created a form with a couple Tab+Grid and the datasource of CustGroup
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
[FormControlEventHandler(formControlStr(TestForm, FormTabControl1), FormControlEventType::TabChanged)]
public static void FormTabControl1_OnTabChanged(FormControl sender, FormControlEventArgs e)
{
// You can interact with FormRun
FormRun formRun = sender.formRun();
// You can interact with the actual control (from event handler)
FormTabControl formTabControl = sender is FormTabControl ? sender as FormTabControl : null;
// You can get events
FormTabControlTabChangedEventArgs formTabControlTabChangedEventArgs = e is FormTabControlTabChangedEventArgs ? e as FormTabControlTabChangedEventArgs : null;
// You can interact with the tab pages
if (formTabControl && formTabControlTabChangedEventArgs)
{
FormControl fc = formTabControl.controlNum(formTabControlTabChangedEventArgs.oldTab());
FormTabPageControl tabPageOld = formTabControl.controlNum(formTabControlTabChangedEventArgs.oldTab());
FormTabPageControl tabPageNew = formTabControl.controlNum(formTabControlTabChangedEventArgs.newTab());
info(strFmt("Tab changed from %1 to %2", tabPageOld.caption(), tabPageNew.caption()));
}
// You can interact with datasources
FormDataSource fdsCustGroup = formRun.dataHelper().FindDataSource('CustGroup');
}
I'm implementing a DynamicItemStart button inside a Menu Controller. I'm loading the dynamic items for this button when Visual Studio starts. Everything is loaded correctly so the initialize method is called an I see all the new items in this Dynamic button. After the package is completely loaded I want to add more items to this Dynamic button, but since the package is already loaded the initialize method is not called again and I cannot see the new items in this Dynamic button. I only see the ones that were loaded when VS started.
Is there any way that I can force the update of this Dynamic button so it shows the new items?. I want to be able to update the VS UI after I added more items but outside the Initialize method.
The implementation I did is very similar to the one showed on this msdn example:
http://msdn.microsoft.com/en-us/library/bb166492.aspx
Does anyone know if an Update of the UI can be done by demand?
Any hints are greatly appreciated.
I finally got this working. The main thing is the implementation of a derived class of OleMenuCommand that implements a new constructor with a Predicate. This predicate is used to check if a new command is a match within the DynamicItemStart button.
public class DynamicItemMenuCommand : OleMenuCommand
{
private Predicate<int> matches;
public DynamicItemMenuCommand(CommandID rootId, Predicate<int> matches, EventHandler invokeHandler, EventHandler beforeQueryStatusHandler)
: base(invokeHandler, null, beforeQueryStatusHandler, rootId)
{
if (matches == null)
{
throw new ArgumentNullException("Matches predicate cannot be null.");
}
this.matches = matches;
}
public override bool DynamicItemMatch(int cmdId)
{
if (this.matches(cmdId))
{
this.MatchedCommandId = cmdId;
return true;
}
this.MatchedCommandId = 0;
return false;
}
}
The above class should be used when adding the commands on execution time. Here's the code that creates the commands
public class ListMenu
{
private int _baselistID = (int)PkgCmdIDList.cmdidMRUList;
private List<IVsDataExplorerConnection> _connectionsList;
public ListMenu(ref OleMenuCommandService mcs)
{
InitMRUMenu(ref mcs);
}
internal void InitMRUMenu(ref OleMenuCommandService mcs)
{
if (mcs != null)
{
//_baselistID has the guid value of the DynamicStartItem
CommandID dynamicItemRootId = new CommandID(GuidList.guidIDEToolbarCmdSet, _baselistID);
DynamicItemMenuCommand dynamicMenuCommand = new DynamicItemMenuCommand(dynamicItemRootId, isValidDynamicItem, OnInvokedDynamicItem, OnBeforeQueryStatusDynamicItem);
mcs.AddCommand(dynamicMenuCommand);
}
}
private bool IsValidDynamicItem(int commandId)
{
return ((commandId - _baselistID) < connectionsCount); // here is the place to put the criteria to add a new command to the dynamic button
}
private void OnInvokedDynamicItem(object sender, EventArgs args)
{
DynamicItemMenuCommand invokedCommand = (DynamicItemMenuCommand)sender;
if (null != invokedCommand)
{
.....
}
}
private void OnBeforeQueryStatusDynamicItem(object sender, EventArgs args)
{
DynamicItemMenuCommand matchedCommand = (DynamicItemMenuCommand)sender;
bool isRootItem = (matchedCommand.MatchedCommandId == 0);
matchedCommand.Enabled = true;
matchedCommand.Visible = true;
int indexForDisplay = (isRootItem ? 0 : (matchedCommand.MatchedCommandId - _baselistID));
matchedCommand.Text = "Text for the command";
matchedCommand.MatchedCommandId = 0;
}
}
I had to review a lot of documentation since it was not very clear how the commands can be added on execution time. So I hope this save some time whoever has to implement anything similar.
The missing piece for me was figuring out how to control the addition of new items.
It took me some time to figure out that the matches predicate (the IsValidDynamicItem method in the sample) controls how many items get added - as long as it returns true, the OnBeforeQueryStatusDynamicItem gets invoked and can set the details (Enabled/Visible/Checked/Text etc.) of the match to be added to the menu.
I'm using IE9 (rtm) at the moment and I am wondering if this is an issue of my own doing or a bug in Internet Explorer 9.
I'm using ASP.NET MVC the form controller is defined as:
[HttpPost()]
[UrlRoute(Path = "Checkout/Cart")]
public ActionResult Cart(ShoppingCartModel cart, string submitButton)
All browsers will cause this method to be hit on post back. The input type is detailed as:
<input type="image" src="/resources/images/removeselected.png" class="rightButton removeSelected" alt="Remove Selected" name="submitButton" value="<%= Html.Encode(Model.REMOVE_SELECTED) %>" />
And here is what is posted back with the form:
Chrome:
CartId=241&submitButton.x=83&submitButton.y=12&submitButton=removeSelected&Items%5B0%5D.Selected=true&Items%5B0%5D.Selected=false&Items%5B0%5D.OrderItemId=76&Items%5B0%5D.Product.ID=9611&Items%5B0%5D.Quantity=1
Internet Explorer 9:
CartId=244&Items%5B0%5D.Selected=true&Items%5B0%5D.Selected=false&Items%5B0%5D.OrderItemId=77&Items%5B0%5D.Product.ID=10091&Items%5B0%5D.Quantity=1&submitButton.x=27&submitButton.y=8
As you can see, Chrome is putting in the submitButton=removeSelected and IE isn't. It works fine in Firefox, also.
If I change it to <input type="submit"> it works without an issue. However, I want to use an IMAGE type
According to the specification:
When a pointing device is used to
click on the image, the form is
submitted and the click coordinates
passed to the server. The x value is
measured in pixels from the left of
the image, and the y value in pixels
from the top of the image. The
submitted data includes name.x=x-value
and name.y=y-value where "name" is the
value of the name attribute, and
x-value and y-value are the x and y
coordinate values, respectively.
You cannot expect more. IE doesn't send submitButton=removeSelected, yes, but there is nothing that obliges is to do so according to the spec. So you should not rely on this parameter. The fact that other browsers are sending it is probably just an implementation detail (on which of course you shouldn't rely).
As a workaround use a normal submit button and try styling it with CSS.
Here's how I got around this; hopefully someone else might find my solution helpful.
The message signature changes; the parameters are a list of all the various form button names. Chrome / FF will fill in these names so you won't need to parse it.
[HttpPost()]
[UrlRoute(Path = "Checkout/Cart")]
public ActionResult Cart(ShoppingCartModel cart, string removeSelected, string nextButton)
{
if (removeSelected == ShoppingCartModel.REMOVE_SELECTED)
removeOp = true;
else if (nextButton == ShoppingCartModel.NEXT_BUTTON)
nextOp = true;
else
{
PostbackButtonParser parser = new PostbackButtonParser(HttpContext.Request.InputStream, new string[] { ShoppingCartModel.NEXT_BUTTON, ShoppingCartModel.REMOVE_SELECTED });
if (parser.PostbackButtonName == ShoppingCartModel.NEXT_BUTTON)
nextOp = true;
else if (parser.PostbackButtonName == ShoppingCartModel.REMOVE_SELECTED)
removeOp = true;
}
if(removeOp) { /* do something */ }
else if (nextOp) { /* do something */ }
}
Then the code to the PostbackButtonParser is fairly straight forward:
/// <summary>
/// Implements a fallback rollover for Internet Explorer and other browsers which don't send the value with an INPUT TYPE="IMAGE" submit.
/// </summary>
/// <example>
/// PostbackButtonParser parser = new PostbackButtonParser(HttpContext.Request.InputStream, new string[] { "button1", "button2" });
/// if(parser.PostbackButtonName == "button1") {
/// // do something
/// }
/// else if (parser.PostbackButtonName == "button2" {
/// // do something else
/// }
/// </example>
/// <remarks>See http://stackoverflow.com/questions/5716260/is-there-a-bug-with-input-type-image-in-internet-explorer</remarks>
public class PostbackButtonParser
{
/// <summary>
/// Gets the name of the button which caused the postback.
/// </summary>
public string PostbackButtonName
{
get;
private set;
}
/// <summary>
/// Creates a new instance of the postback button parser
/// </summary>
/// <param name="requestStream">The stream to process</param>
/// <param name="buttonNames">An array of button names to evaluate gainst</param>
public PostbackButtonParser(Stream requestStream, string[] buttonNames)
{
byte[] stream = new byte[requestStream.Length];
requestStream.Read(stream, 0, stream.Length);
string contents = System.Text.Encoding.ASCII.GetString(stream);
for (int i = 0; i < buttonNames.Length; i++)
{
// Set first match
if (contents.Contains(buttonNames[i] + ".x") && contents.Contains(buttonNames[i] + ".y"))
{
PostbackButtonName = buttonNames[i];
break;
}
}
}
}
I really hope this helps someone; I spent a few hours on what really should have been trivial. What Darin said is very true, I could have styled a but I would rather have used the image type, just for semantics.
I have tried to bind the contents of a textbox to a property I created inside the control, but without success. I have found a way to do it otherwise, but it is convoluted, and I'd prefer something simpler. Anyway, this is the final code:
public partial class DateListEditor : UserControl, INotifyPropertyChanged {
private int _newMonth;
public int newMonth {
get { return _newMonth; }
set {
if(value < 1 || value > 12)
throw new Exception("Invalid month");
_newMonth = value;
NotifyPropertyChanged("newMonth");
}
}
public DateListEditor() {
InitializeComponent();
DataContext = this;
newMonth = DateTime.Now.Month;
}
// ...
Then in the XAML:
<TextBox x:Name="uiMonth" Text="{Binding newMonth, Mode=TwoWay, ValidatesOnExceptions=True}"/>
This thing works. It will pre-fill the textbox with the current month, and validate it when focus is lost: great.
But how can I avoid the XAML line, and do everything from code? I can't seem to be able to work this out. I have tried this code, but nothing happens:
InitializeComponent();
Binding b = new Binding("Text") {
Source = newMonth,
ValidatesOnExceptions = true,
Mode = BindingMode.TwoWay,
};
uiMonth.SetBinding(TextBox.TextProperty, b);
DataContext = this;
How can I do it without setting the binding in the XAML?
Try changing this line and see if it helps
//oldway
Binding b = new Binding("Text")
//newway
Binding b = new Binding("newMonth")
the path you are giving to the Binding should be the Path to the property you want. where you are setting the source you might even be able to leave that blank
+1 tam, and don't forget about the source:
Binding b = new Binding("newMonth"){
Source = this, // the class instance that owns the property 'newMonth'
ValidatesOnExceptions = true,
Mode = BindingMode.TwoWay,
};