Graphics Not Updating in MapView from ViewModel GraphicsOverlay - wpf

I am developing an application with ArcGIS Runtime SDK for .Net and following the MVVM Pattern, in my ViewModel I have an ObservableCollection of GraphicsOverlay that I have binded to the MapView in my View, now when I add a new GraphicsOverlay to the ObservableCollection and add Graphics in it, graphics are not reflection in the View,
I have implemented INotifyPropertyChanged and all other things are working fine with the ViewModel
public class MapViewModel : BaseViewModel
{
private Map map;
public Map Map
{
get { return this.map; }
set { this.map = value; }
}
public ObservableCollection<GraphicsOverlay> GraphicsOverlays { get; set; }
public MapViewModel()
{
GraphicsOverlays = new ObservableCollection<GraphicsOverlay>();
}
And in my Method that is called by any event
public void UpdateMarker(MapPoint point)
{
GraphicsOverlays[0].Graphics.Clear();
// Create a symbol to symbolize the point
SimpleMarkerSymbol symbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.X, System.Drawing.Color.Yellow, 20);
// Create the graphic
Graphic symbolGraphic = new Graphic(point, symbol);
// Add the graphic to the graphics overlay
var newGraphicsOverlay=new GraphicsOverlay();
GraphicsOverlays[0].Graphics.Add(symbolGraphic);
}
And in my View I have
<esri:MapView x:Name="MyMapView" Grid.Column="0" DataContext="
{StaticResource MapVM}" GraphicsOverlays="{Binding GraphicsOverlays}" Map="
{Binding Map}" Cursor="{Binding MapViewCursor}">
I am unable to find any sample that does exactly this, so how to do this, I am new to arcGIS, Thanks in advance.
Update
I have updated the UpdateMarker Method like this
public void UpdateMarker(MapPoint point)
{
GraphicsOverlays[0].Graphics.Clear();
// Create a symbol to symbolize the point
SimpleMarkerSymbol symbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.X, System.Drawing.Color.Yellow, 20);
// Create the graphic
Graphic symbolGraphic = new Graphic(point, symbol);
// Add the graphic to the graphics overlay
var newGraphicsOverlay = new GraphicsOverlay();
newGraphicsOverlay.Graphics.Add(symbolGraphic);
GraphicsOverlays[0] = newGraphicsOverlay;
}
But still the symbol is not showing on the map.

I think you have to use a GraphicsOverlayCollection instead of an ObservableCollection as MapView.GraphicOverlays is a GraphicsOverlayCollection and not an ObservableCollection. Something like
public GraphicsOverlayCollection<GraphicsOverlay> GraphicsOverlays { get; set; }

Related

How to call setter to add my string to list of parent with using xaml?

I'm creating a segment view for iOS and Android with using Xamarin form.
It's working fine if I generate it from code.
But I want to generate it from xaml.
like this.
<local:Segment>
<local:Segmentbutton text="boy">
<local:Segmentbutton text="girl">
<local:Segment>
In my Segment class, it generates buttons and add to lists to control them.
When I generate My Segment with code, looks like this.
List<String> buttonTexts = new List<String>();
buttonTexts.Add ("B");
buttonTexts.Add ("G");
segment = new AXSegment (buttonTexts, 50, Color.FromHex ("#000000"), AppConstants.GlobalColor, Color.FromHex ("#EEEEEE"));
segment.buttonCallback = SexSegmentButtonChanged;
segment.SelectedIndex = 0;
What docs should I look to do it in xaml?
I looked "BindableProperty" or many thins but could not find yet.
I just want trigger SETTER when
<local:Segmentbutton text="boy">
so that I just generate button and add it to my list in MySegment.
Thanks.
ContentPropertyAttribute is the keyword. You have to create:
Segment
Nothing special here, just a Element with a Text property.
public class Segment : Element
{
public static readonly BindableProperty TextProperty = BindableProperty.Create<Segment, string>(p => p.Text, string.Empty);
public string Text
{
get
{
return (string)GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
}
}
}
SegmentedView
Inherits from View. The attribute ContentProperty tells the Xaml-Interpreter/Compiler to stuff every child node into the property called Segments.
[ContentProperty("Segments")]
public class SegmentedView : View
{
private readonly IList<Segment> _segments = new List<Segment>();
public IList<Segment> Segments
{
get { return _segments; }
}
}
SegmentedViewRender
Your custom renderer inherits from a renderer of your choice. Android.Views.View is the type of the native control. You have to change it.
public class SegmentedViewRender : ViewRenderer<SegmentedView, Android.Views.View>
{
protected override void OnElementChanged(ElementChangedEventArgs<SegmentedView> e)
{
base.OnElementChanged(e);
// segments are in: this.Element.Segments
}
}
Usage
<local:SegmentedView>
<local:Segment Text="Bengal"></local:Segment>
<local:Segment Text="Siam"></local:Segment>
<local:Segment Text="Maine Coon"></local:Segment>
</local:SegmentedView>

How to edit elements in a collection from another window or Dialog

I have a number of collection bound to the application main window controls shown in a
simplified form below. There are a number of other elements in the view model
(Ommited for Clarity) which all update and work as expected.
I require to edit a collection's element in another window, with the edited data back in the origonal collection.
/// Example of the Collection and Properties
ObservableCollection<MyData> _MyCollection = new ObservableCollection<MyData>();
public ObservableCollection<MyData> MyCollection { get { return _MyCollection; } }
public class MyData : INotifyPropertyChanged
{
private bool cb_checked;
public string Param1 { get; set; }
public string Param2 { get; set; }
public bool myCheck
{
get { return cb_checked; }
set
{
if (cb_checked == value) return;
cb_checked = value;
RaisePropertyChanged("Checked");
}
}
}
My problem is how do I pass an item of a collection to a new window for editing.
My intal thoughts were to pass the item in the constructor of the window
Dialog.Edit window = new Dialog.Edit(_MyCollection[2] );
window.Owner = this;
window.Show();
I also tried this as I have read I cant use indexed references
var tmp = _MyCollection[2];
Dialog.Edit window = new Dialog.Edit( tmp);
window.Owner = this;
window.Show();
but this does not work and I get null exceptions whe trying to access elements.
If I need to pass the complete collection this is also ok as they are all quite small i.e. < 50 items.
I must be going about this in the wrong way, could someone please explain how to do this
correctly please.
Many Thanks
Sarah

Where do I put the logic for my ICommand?

I've recently started using the MVVM pattern in silverlight, and i'm not sure if i am using it correctly.
GUI
I currently have a MainView that has combobox of stock market sectors. When the user selects a sector (eg ENERGY) and clicks the Add button a list of stocks for that sector are displayed in a listbox. By the side of each stock in the listbox is a remove button that allows you to remove the individual stock from the listbox.
I have implemented the following ViewModels. (Below is just an indication of the code)
public class MainViewModel
{
public SectorViewModel CurrentSector
{
get;
set;
}
public string SelectedSector
{
get;
set;
}
public void AddSectorClickedCommand()
{
CurrentSector = new SectorViewModel(SelectedSector);
}
}
public class SectorViewModel
{
public ObservableCollection<StockViewModel> Stocks = new ObservableCollection<StockViewModel>();
public SectorViewModel(string sector)
{
List<Stocks> stocklist = StockProvider.GetStocks(sector);
for each (var s in stocklist)
{
StockViewModel svm = new StockViewModel(s);
svm.Remove+= { //Remove svm from Stocks collection logic
Stocks.add(svm);
}
}
}
My question is; in whcih viewmodel is it best to add the code implementation for the Remove button of each row in the listbox?? The Remove button should remove the StockViewModel from the SectorViewModel.Stocks collection.
I have currently added the RemoveClicked method to the StockViewModel(as shown above). This code fires an event back to the SectorViewModel and the RemoveStock method of the SectorViewModel removes the StockViewModel from the Stock collection.
Is there a better way to implement this remove functionality? I'm new to MVVM and am not sure if this is the best approach to develop this functionility, since the SectorViewModel needs to register to events of a StockViewModel.
Personally I don't like events because you should unsubscribe from them and also they can be used where it isn't appropriate.
I would use the constructor parameter to handle the remove command, something like this:
public class StockViewModel
{
public StockViewModel(Stock stock, Action<StockViewModel> removeCommandAction)
{
//...
this.RemoveCommand = new DelegateCommand(() => removeCommandAction(this));
}
}
public class SectorViewModel
{
public SectorViewModel()
{
//...
StockViewModel svm = new StockViewModel(s, this.RemoveStock);
Stocks.add(svm);
}
private void RemoveStock(StockViewModel stock)
{
//...
}
}
Another approach is to use some kind of the EventAggregator pattern, for example, the Messenger class from the MVVM light Toolkit. But I think that it is an overkill for such simple task:
public StockViewModel(Stock stock, IMessenger messenger)
{
//...
this.RemoveCommand = new DelegateCommand(() =>
messenger.Send(new NotificationMessage<StockViewModel>(this, RemoveItemNotification)));
}
public SectorViewModel(IMessenger messenger)
{
//...
messenger.Register<NotificationMessage<StockViewModel>>(this, msg =>
{
if (msg.Notification == StockViewModel.RemoveItemNotification)
{
this.RemoveStock(msg.Content);
}
}
}
Also I heard that Silverlight 5 supports binding to a relative source.
So there is the 3rd approach. I'm not sure whether this example works, but at least it should:
<Button Content="Remove"
Command="{Binding DataContext.RemoveCommand RelativeSource={RelativeSource AncestorType=ListBox}}"
CommandParameter="{Binding}" />
public class SectorViewModel
{
public SectorViewModel()
{
this.RemoveCommand = new DelegateCommand(obj => this.RemoveStock((StockViewModel)obj));
}
public ICommand RemoveCommand { get; set; }
}
The last example is the most preferred by the way and is used in WPF applications because WPF has always had RelativeSource binding.

Open new Window from view model

Hi I have a beginner problem. I have shell (it is wpf window) and in this shell is screen (it is an user control / view model).
I would like open new window from view model, not show user control in shell.
So I create new window - ChatView
<Window x:Class="Spirit.Views.ChatView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:extToolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit.Extended" Title="ChatView" Height="545" Width="763">
<Grid Margin="4,4,4,4">
</Grid>
</Window>
Export ChatViewModel with MEF.
public interface IChatViewModel
{
}
[Export("ChatScreen",typeof(IChatViewModel))]
public class ChatViewModel
{
}
In view model I have this method:
With ShowScreen class help me Mr.Marco Amendola. It look likes this:
public class ShowScreen : IResult
{
readonly Type _screenType;
readonly string _name;
[Import]
public IShellViewModel Shell { get; set; }
Action<object> _initializationAction = screen => { };
public ShowScreen InitializeWith<T>(T argument)
{
_initializationAction = screen =>
{
var initializable = screen as IInitializable<T>;
if (initializable != null)
initializable.Initialize(argument);
};
return this;
}
public ShowScreen(string name)
{
_name = name;
}
public ShowScreen(Type screenType)
{
_screenType = screenType;
}
public void Execute(ActionExecutionContext context)
{
var screen = !string.IsNullOrEmpty(_name)
? IoC.Get<object>(_name)
: IoC.GetInstance(_screenType, null);
_initializationAction(screen);
Shell.ActivateItem(screen);
Completed(this, new ResultCompletionEventArgs());
}
public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
public static ShowScreen Of<T>()
{
return new ShowScreen(typeof(T));
}
}
My problem is if I try show new window it doesn’t works, it works only if I show new user control in shell(window).
I would like achieve behavior something like in skype. You have a main window with listbox, you double clicked on item and it show new chat window.
Main window can publish with EventAggregator on chat window and also chat window can publish on main window. This is my goal.
I know that I can not use class ShowScreen on showing new Window. I would like to know what is correct way to create new window from view model and inject event aggregator
to this vie model.
Any advice? Thank for your help and time.
Have you looked at WindowManager.Show or WindowManager.ShowDialog? Rob has a sample at http://caliburnmicro.codeplex.com/wikipage?title=The%20Window%20Manager. You can inject this dependency into your view model as IWindowManager.
I'm using this. Maybe could save a question about "where's the code ?".
DialogHelper:
public class DialogHelper
{
public void ShowDialog<T>(params Object[] param) where T : class
{
var windowManager = new WindowManager();
T viewModel = Activator.CreateInstance(typeof(T), param) as T;
windowManager.ShowWindow(viewModel);
}
}
How to use:
Without constructor parameter:
Dialog.ShowDialog<TestTableViewModel>();
With constructor paramater:
Dialog.ShowDialog<TestTableViewModel>(dt);
Note that I'm not using MEF

Silverlight View exporting DependencyProperty to ViewModel via MEF

I have a need of one DependencyProperty from a View in my ViewModel constructor:
My problem: MEF wouldn't SatisfyImports() 'because it is marked with one or more ExportAttributes' (that is the exception)
This is the code structure for the VIEW:
public class MyView : UserControl
{
[Export(MethodTypes.ChartType)]
public Charts MyChartType
{
get
{
object k = GetValue(ChartTypeProperty);
Charts f = (Charts)Enum.Parse(typeof(Charts), k.ToString(), true);
return f;
}
set
{
SetValue(ChartTypeProperty, value);
}
}
[Import(ViewModelTypes.GenericChartViewModel)]
public object ViewModel
{
set
{
DataContext = value;
}
}
public MyView()
{
InitializeComponent();
if (!ViewModelBase.IsInDesignModeStatic)
{
// Use MEF To load the View Model
CompositionInitializer.SatisfyImports(this);
}
}
}
and the VIEWMODEL:
[PartCreationPolicy(CreationPolicy.NonShared)]
[Export(ViewModelTypes.GenericChartViewModel)]
public class GenericChartViewModel
{
[ImportingConstructor]
public GenericChartViewModel([Import(MethodTypes.ChartType)] Charts forChartType)
{
string test = forChartType.ToString();
}
}
Please give me any hints on this or maybe suggest a better solution for passing parameters through mef
In my case, I would need to pass only dependecyproperty's for now...
Thanks
Your work around isn't really good.. can't you remove the export from ChartTypes and pass it manually to whoever wants it? I presume the viewmodel is only one insterested in it..
I managed to put this through !
Instead of the code in the default constructor, I use:
void MyView_Loaded(object sender, RoutedEventArgs e)
{
if (!ViewModelBase.IsInDesignModeStatic)
{
var catalog = new TypeCatalog(typeof(GenericChartViewModel));
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
and the dependencyproperty value is correctly propagated to the ViewModel
(must do this after control is loaded, or the property will have its default value)
However, I would be very grateful if someone could:
tell me how generate a catalog from another non-referenced assembly?
Thanks

Resources