|
POST
|
I would be very interested on benchmarks about WPF rendering and DirextX rendering in different cases. One specific point would also be that what kind of overhead is to change a graphic or 100 graphics from WPF rendering to Accelerated rendering and vice verse. Also I would pleased if someone from Runtime team could open a curtain what really happens when the WPF control is drawing stuff in DirectX and how the information ends up to DirectX rendering pipeline.
... View more
08-03-2012
01:11 AM
|
0
|
0
|
1832
|
|
POST
|
I agree that things are a bit messy in this sense. There are some issues that are pain to work with when using MVVM, but now we unfortunately have to live with it. 😞
... View more
08-02-2012
10:53 PM
|
0
|
0
|
207
|
|
POST
|
If I understood correctly what you are trying to do, I think you should just use Graphic's Attributes when changing the values in the edit boxes and bind directly to those. So when user changes the value of the Graphic do the change directly to Attribute[key]. If I missed something let me know and I try to look it a bit more closely. Edit: Check ArcGIS Runtime SDK for WPF sample : Editing - EditControls - Feature Data Form that might help a bit.
... View more
08-02-2012
03:05 AM
|
0
|
0
|
758
|
|
POST
|
1. Store pure identifier in Attributes or parse Meter Number:xxxxx format when querying the Graphic. 2. When looking correct graphic from GraphicsLayer enumerate graphicsLayer.Graphics and look correct item like this in pseudocode
var foundItem = graphicsLayer.Graphics.FirstOrDefault(x => x.Attributes["identifierName"].ToString == variableThatWeAreLookingFor);
if (foundItem != null)
{
Do stuff
}
Code assumes that graphics has "identifierName attribute but if you are not sure if that is included, then loop in foreach loop and check if the attribute contains that with ContainsKey("indentifierName").
... View more
08-02-2012
02:57 AM
|
0
|
0
|
647
|
|
POST
|
First make sure that you have reference to needed assemblies: Click References open in the solution explorer and check that you have ESRI.ArcGIS.Client and ESRI.ArgGIS.ClientToolkit in the list. If not, add them. If on compile time Visual Studio is saying something about serialization add System.Runtime.Serialization to your project. Then copy code: 1. Copy XAML part from 2nd row (from the example) until the end and copy that to your main page from 2nd row so your main page should look like this:
<UserControl x:Class="SilverlightApplication3.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:esri="http://schemas.esri.com/arcgis/client/2009">
<Grid x:Name="LayoutRoot" Background="White">
<esri:Map x:Name="MyMap" WrapAround="True" Extent="-15000000,2000000,-7000000,8000000">
<esri:ArcGISTiledMapServiceLayer ID="StreetLayer"
Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" />
</esri:Map>
<Grid HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,10,10,0" >
<Rectangle Fill="#77919191" Stroke="Gray" RadiusX="10" RadiusY="10" Margin="0,0,0,5" >
<Rectangle.Effect>
<DropShadowEffect/>
</Rectangle.Effect>
</Rectangle>
<Rectangle Fill="#66FFFFFF" Stroke="DarkGray" RadiusX="5" RadiusY="5" Margin="10,10,10,15" />
<Image x:Name="MyMagnifyImage" Source="/Assets/images/magglass.png" Canvas.ZIndex="10" Margin="25, 20, 20, 25"
Stretch="UniformToFill" Width="32" Height="50"
MouseLeftButtonDown="MyMagnifyImage_MouseLeftButtonDown" />
</Grid>
<Canvas>
<esri:Magnifier x:Name="MyMagnifier" ZoomFactor="3" Canvas.ZIndex="10" Map="{Binding ElementName=MyMap}" >
<esri:Magnifier.Layers>
<esri:ArcGISTiledMapServiceLayer ID="MagnifyImageLayer"
Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer" />
</esri:Magnifier.Layers>
</esri:Magnifier>
</Canvas>
</Grid>
</UserControl>
2. Copy private void MyMagnifyImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
MyMagnifier.Enabled = !MyMagnifier.Enabled;
}
from the example CS tab to your MainPage.xaml.CS file after constructor
public MainPage() { InitializeComponent(); } private void MyMagnifyImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { MyMagnifier.Enabled = !MyMagnifier.Enabled; } Compile and have fun. If you have more questions about this, let me know and mark to answered if you got things to work.
... View more
08-02-2012
02:29 AM
|
0
|
0
|
984
|
|
POST
|
Why use a workaround when you can just utilize the "Binding" keyword and make the platform do all the rest of the work for you? At my knowledge, the issue here is that you need to explicitly define source for your binding when binding from non-visual elements (layers in this case) to something. Since layers aren't part of the visual tree, they do not get the DataContext derived from the upper elements so we need to proxy the DataContext somehow to the non-visual elements in XAML.
... View more
08-02-2012
01:45 AM
|
0
|
0
|
1460
|
|
POST
|
Edit: Here is one solution to store graphics locally but you should store stuff to your database if you can. In my case, we needed to store non-saved graphics temporarely so I came up with this kind of idea Edit end. Long time ago I wrote serialization extensions for Silverlight and I just ported that to WPF to see if the solution works also in it and with fast test it seems more or less to work. <br><br>The idea was to save deserialized information to string that you can save to file or database. In serialization I use XamlWriter internally. The systems works like this: You define graphics layer you want to store
<esri:GraphicsLayer ID="glayer" x:Name="glayer">
Add execution logic (here 2 buttons with clicks to keep sample clean)
<Button Click="SerializeClick">Serialize</Button>
<Button Click="DeserializeClick">Deserialize</Button>
private string serializedData;
private void SerializeClick(object sender, RoutedEventArgs e)
{
var graphicsLayer = Map.Layers["glayer"] as GraphicsLayer;
// Serialize layer and set result to private variable
this.serializedData = graphicsLayer.SerializeGraphics();
graphicsLayer.ClearGraphics();
}
private void DeserializeClick(object sender, RoutedEventArgs e)
{
var graphicsLayer = Map.Layers["glayer"] as GraphicsLayer;
graphicsLayer.DeserializeGraphics(this.serializedData);
// Reset serialized data
this.serializedData = string.Empty;
}
Here you have serializedData string that contains the serialized data. Now you can do what you want with it. NOTE: I haven't tested this solution in WPF more then this example! The solution should be reviewed in code level to make it more WPF and newest ArcGIS API opitimized. When I wrote that we didnt have stuff like ToJson() and Silverlight does not support XamlWriter out of the box so thing might work differently in WPF than in Silverlight. What we did in Silverlight, we created quite large graphic writing capabilities with opacity controls, border and fill customizations etc. and that worked quite well even thou in larger objects the serialized string is huge but that did the work. Here are sample app how I tested the porting. Also if someone is brave (or grazy) enough to my solution in their code, let me know (private message) and I will test / clean this solution and give the assembly or even code to do it if you really need it.
... View more
08-02-2012
01:32 AM
|
0
|
0
|
767
|
|
POST
|
Can you give more details about the use case? If you mean that user could change symbology that is defined in the Services, then I quess not. But if you are using application defined symbols, then you can build functionality to change those on the fly if you really want to. If you create user based symboling system, you need to decide symbol in code after the graphic is loaded from the server or created in the application. Hope this helps. If not, let me know and I might try to build one later on.
... View more
08-01-2012
11:55 PM
|
0
|
0
|
718
|
|
POST
|
I have been thinking ways to leverage both Accelerated and non-Accelerated layers with graphics to work together to gain most of the performance out from drawing, so this is very interesting topic. Since AcceleratedLayers does not support ControlTemplates so visual states and animations are out of the picture which makes ie. Selected state indication quite hard. So far the best solution that I have used is to work simultaneously with one accelerated layer and one normal layer and changing the graphic from layer to layer when selected. I haven't checked the performance with huge amount of graphics but this way I can use accelerated graphics when the graphic is in normal state and use animation when it is selected. What do you guys think about this approach? In this test I baked mouse click on the graphic in ViewModel to keep things simple and on click I change collection accordingly if the graphic is selected or not.
<Window.Resources>
<esri:SimpleRenderer x:Key="MySimpleRenderer">
<esri:SimpleRenderer.Symbol>
<esri:SimpleMarkerSymbol Color="Black" Size="10"/>
</esri:SimpleRenderer.Symbol>
</esri:SimpleRenderer>
<esri:SimpleRenderer x:Key="SelectedRenderer">
<esri:SimpleMarkerSymbol>
<esri:SimpleMarkerSymbol.ControlTemplate>
<ControlTemplate>
<Grid Margin="-19,-19,0,0">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Selected">
<Storyboard RepeatBehavior="Forever">
<DoubleAnimation BeginTime="0"
Storyboard.TargetName="ellipse" Storyboard.TargetProperty="RenderTransform.(ScaleTransform.ScaleX)"
From="1" To="10" Duration="00:00:01" />
<DoubleAnimation BeginTime="0"
Storyboard.TargetName="ellipse" Storyboard.TargetProperty="RenderTransform.(ScaleTransform.ScaleY)"
From="1" To="10" Duration="00:00:01" />
<DoubleAnimation BeginTime="0"
Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.Opacity)"
From="1" To="0" Duration="00:00:01" />
</Storyboard>
</VisualState>
<VisualState x:Name="Unselected" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse x:Name="ellipse" Width="10" Height="10" Stroke="Red" StrokeThickness="1" IsHitTestVisible="False" RenderTransformOrigin="0.5,0.5" >
<Ellipse.RenderTransform>
<ScaleTransform />
</Ellipse.RenderTransform>
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Color="#00FF0000" />
<GradientStop Color="#FFFF0000" Offset="0.25"/>
<GradientStop Color="#00FF0000" Offset="0.5"/>
<GradientStop Color="#FFFF0000" Offset="0.75"/>
<GradientStop Color="#00FF0000" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse Fill="Red" Width="38" Height="38" Stroke="White" StrokeThickness="1"/>
</Grid>
</ControlTemplate>
</esri:SimpleMarkerSymbol.ControlTemplate>
</esri:SimpleMarkerSymbol>
</esri:SimpleRenderer>
</Window.Resources>
<Grid>
<esri:Map>
<esri:Map.Resources>
<local:DataContextProxy x:Key="proxy" Data="{Binding}"/>
</esri:Map.Resources>
<esri:AcceleratedDisplayLayers>
<esri:ArcGISTiledMapServiceLayer ID="PhysicalTiledLayer"
Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/>
<esri:GraphicsLayer ID="MyGraphicsLayer"
GraphicsSource="{Binding Path=Data.SearchResults, Source={StaticResource proxy}}"
Renderer="{StaticResource MySimpleRenderer}" />
</esri:AcceleratedDisplayLayers>
<esri:GraphicsLayer ID="SelectedGraphics"
GraphicsSource="{Binding Path=Data.SelectedGraphics, Source={StaticResource proxy}}"
Renderer="{StaticResource SelectedRenderer}">
</esri:GraphicsLayer>
</esri:Map>
</Grid>
Edit: Added image [ATTACH=CONFIG]16563[/ATTACH]
... View more
08-01-2012
11:43 PM
|
0
|
0
|
1832
|
|
POST
|
Just noting that if you are working with .Net Framework 4.5, you can use MarkupExtensions with Events so you can use similar approach (CommandGenerator) with Events there. In my opinion, its about the time! You can read more from http://blogs.microsoft.co.il/blogs/pavely/archive/2012/04/07/wpf-4-5-markup-extension-for-events.aspx
... View more
08-01-2012
10:14 PM
|
0
|
0
|
1639
|
|
POST
|
To Jeff, I am glad if you found that useful. I think that this is a quite clean solution and does the trick. From my perspective pros of the solution are: it is easy to understand and implement DataContext changes are reflected all way to bindings you can control what data to proxy Minimal overhead And cons: If you want to proxy multiple properties, you need to make multiple proxyproperties. I use this mainly to proxy the DataContext so its fine for me. You need to prefix path in bindings (annoying but I can live with that) If you find situations where the solution does not work, let me know. I am still testing this solution since it is not a long ago when I made this. To original poster, If the post answered to your problem, please mark to answered.
... View more
08-01-2012
09:34 PM
|
0
|
0
|
1460
|
|
POST
|
I checked fast if I could make this work in ItemsControl but didn't figure right away if that is possible. One solution that you can use here is to make AttachedProperty that takes ObservableCollection<YourModel/Graphic/WhatEver> and on bind changes creates / removes InfoWindows from /to Map's parent panel (assuming you have that kind of structure). This is not the cleanest way to handle this kind of problem but with fast test seems to work more or less. Here is some test code that you could use to implement this kind of solution. Here is rough structure how to make this happen:
public class InfoWindowManager : DependencyObject
{
// Contains mapping between the graphic and infowindow
private static readonly List<Tuple<Graphic, InfoWindow>> itemMap = new List<Tuple<Graphic, InfoWindow>>();
// Contains reference to map
private static Map map;
// Panel where map is located
private static Panel parentPanel;
// Dependency property to work bind collection of Graphics that are assosiated with info window
public static readonly DependencyProperty InfoWindowsProperty =
DependencyProperty.RegisterAttached(
"InfoWindows",
typeof(ObservableCollection<Graphic>),
typeof(InfoWindowManager),
new PropertyMetadata(OnInfoWindowsPropertyChanged));
public static void SetInfoWindows(UIElement element, ObservableCollection<Graphic> value)
{
element.SetValue(InfoWindowsProperty, value);
}
public static ObservableCollection<Graphic> GetInfoWindows(UIElement element)
{
return (ObservableCollection<Graphic>)element.GetValue(InfoWindowsProperty);
}
// Map colleciton binding
private static void OnInfoWindowsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var targetMap = d as Map;
if (targetMap != null)
{
map = targetMap;
parentPanel = map.Parent as Panel;
}
var oldList = e.OldValue as ObservableCollection<Graphic>;
if (oldList != null)
{
oldList.CollectionChanged -= OnCollectionChanged;
}
var newList = e.NewValue as ObservableCollection<Graphic>;
if (newList != null)
{
newList.CollectionChanged += OnCollectionChanged;
// Add items that are in the collection on bind time
foreach (var item in newList)
{
AddItem(item);
}
}
}
// Occurs when binded collection is changed
private static void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Reset)
{
var itemsToRemove = parentPanel.Children.OfType<InfoWindow>().ToList();
if (itemsToRemove.Count > 0)
{
itemsToRemove.ForEach(x => parentPanel.Children.Remove(x));
itemMap.Clear();
}
}
if (e.NewItems != null)
{
// Add new items
foreach (Graphic item in e.NewItems)
{
AddItem(item);
}
}
if (e.OldItems != null)
{
// Remove all old items.
foreach (Graphic item in e.OldItems)
{
var info = itemMap.FirstOrDefault(x => x.Item1 == item);
if (info != null)
{
parentPanel.Children.Remove(info.Item2);
itemMap.Remove(info);
}
}
}
}
private static void AddItem(Graphic itemToAdd)
{
// Create infowindow and set properties
var info = new InfoWindow
{
Anchor = itemToAdd.Geometry as MapPoint,
IsOpen = true,
Content = itemToAdd.Attributes,
Map = map
};
// Add infowindow to layout structure
parentPanel.Children.Add(info);
// Add mapping with graphic and infowindow
itemMap.Add(new Tuple<Graphic, InfoWindow>(itemToAdd, info));
}
}
And in the xaml you can bind to this like this. Note that in this case i have ViewModel with ObservableCollection<Graphic> and I bind those to GraphicsLayer using DataContextProxy class that I used in http://forums.arcgis.com/threads/63189-GpsLayer-and-MVVM-issues example. Here you might want to have 2 separate lists, another to graphics to draw and another with graphics that contains those who should have infowindow opened.
<Grid>
<Grid.Resources>
<local:DataContextProxy x:Key="proxy" Data="{Binding}" />
<Style TargetType="{x:Type esri:InfoWindow}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding [CREATED]}" Foreground="Red" FontSize="12" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<esri:Map local:InfoWindowManager.InfoWindows="{Binding SearchResults}">
<esri:ArcGISTiledMapServiceLayer ID="PhysicalTiledLayer"
Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/>
<esri:GraphicsLayer ID="MyGraphicsLayer"
GraphicsSource="{Binding Path=Data.SearchResults, Source={StaticResource proxy}}"
Renderer="{StaticResource MySimpleRenderer}" />
</esri:Map>
</Grid>
Not sure if this helps but atleast I had fun creating it 🙂 Edit: Added image from test solution [ATTACH=CONFIG]16538[/ATTACH]
... View more
08-01-2012
04:56 AM
|
0
|
0
|
572
|
|
POST
|
When working with Caliburn.Micro you can use DataContextProxy to define DataContext from the Map so you can bind to it since Caliburn handles ViewModel mapping automatically. DataContext can be proxied with solution like this: public class DataContextProxy : Freezable { #region Overrides of Freezable protected override Freezable CreateInstanceCore() { return new DataContextProxy(); } #endregion public object Data { get { return (object)GetValue(DataProperty); } set { SetValue(DataProperty, value); } } public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object), typeof(DataContextProxy), new UIPropertyMetadata(null)); } And in the XAML you can use it like this <esri:Map> <esri:Map.Resources> <local:DataContextProxy x:Key="proxy" Data="{Binding}" /> </esri:Map.Resources> <esri:ArcGISTiledMapServiceLayer ID="PhysicalTiledLayer" Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/> <esri:GraphicsLayer ID="MyGraphicsLayer" GraphicsSource="{Binding Path=Data.SearchResults, Source={StaticResource proxy}}" Renderer="{StaticResource MySimpleRenderer}" /> </esri:Map> This is just one solution but seems to work quite well in the cases where you don't set ViewModels explicitly in the XAML. Edit: Note that when using proxy like this, you need to prefix binding to real proxy property since the solution is kind of relative binding. In this case, path is set to Data.SearchResults.
... View more
07-31-2012
11:14 PM
|
0
|
0
|
1460
|
|
POST
|
You can't do that with current build but you should be able to create normal WPF application (desktop side application) in 4.5 framework in VS 2012. I tried it, but it's impossible even to add reference to Runtime SDK in Metrostyle application.
... View more
07-01-2012
10:52 PM
|
0
|
0
|
1721
|
|
POST
|
Hi, Does version 1.0 of ArcGIS Runtime SDK for WPF contain API for developing Metrostyle applications (Windows 😎 as demonstrated in Developers Summit? Best Regards, Dima. No it doesn't, that is developed in totally different product line. Actually current download does not support Visual Studio 12 at all since it requires Visual Studio 2010 SP 1 installed. Haven't tested if I can install current build to machine with both 2010 and 2012 and then use Runtime in 4.5 projects at VS 2012. If someone has done that, did it work or is there coming VS2012 version with 4.5 support?
... View more
07-01-2012
10:32 PM
|
0
|
0
|
1721
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 11-12-2014 03:52 AM | |
| 1 | 08-27-2015 03:47 AM | |
| 1 | 12-08-2014 09:58 AM | |
| 1 | 05-05-2015 10:19 AM | |
| 1 | 07-30-2015 08:43 AM |
| Online Status |
Offline
|
| Date Last Visited |
11-11-2020
02:23 AM
|