2012-06-08 17 views
14

Tôi đang làm việc trên dự án bề mặt này, nơi chúng tôi có kiểm soát bản đồ bing và nơi chúng tôi muốn vẽ polylines trên bản đồ, bằng cách sử dụng databinding.WPF bing maps kiểm soát các polylines/polygon không vẽ trên đầu tiên thêm vào bộ sưu tập

Hành vi lạ xảy ra là khi tôi nhấp vào nút Thêm, không có gì xảy ra trên bản đồ. Nếu tôi di chuyển bản đồ một chút, đường polyline sẽ được vẽ trên bản đồ. Một kịch bản khác mà loại công trình, là nhấp vào nút thêm một lần, không có gì xảy ra, bấm vào nó một lần nữa cả hai polylines được rút ra. (Trong bộ sưu tập thủ công của tôi, tôi có 4 LocationCollections) vì vậy điều tương tự cũng xảy ra cho lần nhấp thứ 3 và nhấp chuột thứ tư, nơi cả hai dòng được vẽ.

Tôi hoàn toàn không biết phải tìm đâu nữa để sửa lỗi này. Tôi đã thử đăng ký các sự kiện Layoutupdated, xảy ra trong cả hai trường hợp. Cũng đã thêm một sự kiện được sưu tầm vào bộ quan sát để xem liệu phần bổ sung có được kích hoạt hay không và nó được kích hoạt. Một điều tôi đã cố gắng là thay đổi polyline để pushpin và có vị trí đầu tiên từ bộ sưu tập các vị trí trong pipelineviewmodel, hơn là nó làm việc một mong đợi.

Tôi đã tải lên sample project nếu bạn muốn thấy chính mình điều gì đang xảy ra.

Thực sự hy vọng rằng ai đó có thể chỉ cho tôi đúng hướng, bởi vì tôi không còn manh mối nữa.

Dưới đây bạn tìm thấy mã mà tôi đã viết:

Tôi có viewmodels sau:

MainViewModel

public class MainViewModel 
{ 
    private ObservableCollection<PipelineViewModel> _pipelines; 

    public ObservableCollection<PipelineViewModel> Pipes 
    { 
     get { return _pipelines; } 
    } 

    public MainViewModel() 
    { 
     _pipelines = new ObservableCollection<PipelineViewModel>(); 
    } 
} 

Và PipelineViewModel trong đó có bộ sưu tập các địa điểm mà thực hiện INotifyPropertyChanged :

Pipelin eViewModel

public class PipelineViewModel : ViewModelBase 
{ 
    private LocationCollection _locations; 

    public string Geometry { get; set; } 
    public string Label { get; set; } 
    public LocationCollection Locations 
    { 
     get { return _locations; } 
     set 
     { 
      _locations = value; 
      RaisePropertyChanged("Locations"); 
     } 
    } 
} 

XAML của tôi trông giống như dưới đây:

<s:SurfaceWindow x:Class="SurfaceApplication3.SurfaceWindow1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:s="http://schemas.microsoft.com/surface/2008" 
    xmlns:m="clr-namespace:Microsoft.Maps.MapControl.WPF;assembly=Microsoft.Maps.MapControl.WPF" 
    Title="SurfaceApplication3"> 
    <s:SurfaceWindow.Resources> 
     <DataTemplate x:Key="Poly"> 
      <m:MapPolyline Locations="{Binding Locations}" Stroke="Black" StrokeThickness="5" /> 
     </DataTemplate> 
    </s:SurfaceWindow.Resources> 
    <Grid> 
     <m:Map ZoomLevel="8" Center="52.332074,5.542302" Name="Map"> 
      <m:MapItemsControl Name="x" ItemsSource="{Binding Pipes}" ItemTemplate="{StaticResource Poly}" /> 
     </m:Map> 
     <Button Name="add" Width="100" Height="50" Content="Add" Click="add_Click"></Button> 
    </Grid> 
</s:SurfaceWindow> 

Và trong codebehind của chúng tôi, chúng tôi đang thiết lập các ràng buộc và sự kiện nhấp chuột như thế này:

private int _counter = 0; 
private string[] geoLines; 

private MainViewModel _mainViewModel = new MainViewModel(); 

/// <summary> 
/// Default constructor. 
/// </summary> 
public SurfaceWindow1() 
{ 
    InitializeComponent(); 

    // Add handlers for window availability events 
    AddWindowAvailabilityHandlers(); 

    this.DataContext = _mainViewModel; 

    geoLines = new string[4]{ "52.588032,5.979309; 52.491143,6.020508; 52.397391,5.929871; 52.269838,5.957336; 52.224435,5.696411; 52.071065,5.740356", 
           "52.539614,4.902649; 52.429222,4.801025; 52.308479,4.86145; 52.246301,4.669189; 52.217704,4.836731; 52.313516,5.048218", 
           "51.840869,4.394531; 51.8731,4.866943; 51.99841,5.122375; 52.178985,5.438232; 51.8731,5.701904; 52.071065,6.421509", 
           "51.633362,4.111633; 51.923943,6.193542; 52.561325,5.28717; 52.561325,6.25946; 51.524125,5.427246; 51.937492,5.28717" }; 
} 

private void add_Click(object sender, RoutedEventArgs e) 
{ 
    PipelineViewModel plv = new PipelineViewModel(); 
    plv.Locations = AddLinestring(geoLines[_counter]); 
    plv.Geometry = geoLines[_counter]; 

    _mainViewModel.Pipes.Add(plv); 

    _counter++; 
} 

private LocationCollection AddLinestring(string shapegeo) 
{ 
    LocationCollection shapeCollection = new LocationCollection(); 

    string[] lines = Regex.Split(shapegeo, ";"); 
    foreach (string line in lines) 
    { 
     string[] pts = Regex.Split(line, ","); 

     double lon = double.Parse(pts[1], new CultureInfo("en-GB")); 
     double lat = double.Parse(pts[0], new CultureInfo("en-GB")); 
     shapeCollection.Add(new Location(lat, lon)); 
    } 

    return shapeCollection; 
} 
+0

tôi không thể giúp bạn về vấn đề này nhưng đã thử nghiệm dự án mẫu của bạn; đã thực hiện một số công cụ thử nghiệm và lỗi (Không hợp lệ, buộc di chuyển bản đồ) nhưng cũng không có đầu mối tại sao nó không hoạt động. Mọi thứ bạn đã thực hiện đều ổn. Nhưng đây là một số phát hiện: Thêm MapPolyline từ CodeBehind hoạt động tốt. Nếu bạn sử dụng một yếu tố khác như Pushpin, nó cũng hoạt động tốt. Vì vậy, vấn đề phải làm với tất cả những thứ thừa kế từ MapShapeBase.Và đó là MapPolyline và MapPolygon. Tôi đã có một cái nhìn về nó thông qua Reflector và cố gắng để so sánh việc thực hiện Pushpin với việc thực hiện MapPolyline. – SvenG

+0

Tôi không thể đầu tư thêm thời gian, nhưng nếu tôi có thể gỡ lỗi mã phản chiếu và xem tại sao một Đinh ghim được làm mới chính xác nhưng MapPolyLine/MapPolygon thì không. – SvenG

+0

Xin chào SvenG, Cảm ơn bạn đã dành thời gian xem nó. Có, tôi đã thấy rằng các pushpins chỉ làm việc tốt. Tôi cũng đã gọi phương thức UpdateLayout() trên MapItemsControl và thêm một UIElement rỗng vào lớp và nó sẽ hiển thị polyline. Vẫn còn hav eno đầu mối tại sao nó không hoạt động: ( – ChristiaanV

Trả lời

14

tôi đã làm một số đào về vấn đề này và thấy rằng có một lỗi trong việc thực hiện Map. Tôi cũng làm một workaround cho nó có thể được sử dụng như thế này

<m:Map ...> 
    <m:MapItemsControl Name="x" 
         behaviors:MapFixBehavior.FixUpdate="True"/> 
</m:Map> 

tôi bao gồm sửa chữa này trong ứng dụng mẫu của bạn và tải lên nó ở đây: SurfaceApplication3.zip


Cây thị giác cho mỗi ContentPresenter trông như thế này

enter image description here

Khi bạn thêm một mục mới vào bộ sưu tập các Polygon được thứ e sai Points ban đầu. Thay vì các giá trị như 59, 29, nó nhận được một cái gì đó như 0.0009, 0.00044.

Những điểm được tính bằng MeasureOverride trong MapShapeBase và phần mà không tính trông như thế này

MapMath.TryLocationToViewportPoint(ref this._NormalizedMercatorToViewport, location, out point2); 

Ban đầu, _NormalizedMercatorToViewport sẽ có giá trị mặc định của nó (tất cả mọi thứ được đặt thành 0) nên tính toán đi sai hết. _NormalizedMercatorToViewport được đặt theo phương thức SetView được gọi từ MeasureOverride trong MapLayer.

MeasureOverride trong MapLayer có hai câu lệnh if sau.

if ((element is ContentPresenter) && (VisualTreeHelper.GetChildrenCount(element) > 0)) 
{ 
    child.SetView(...) 
} 

này đi ra như falseContentPresenter đã không có một đứa trẻ hình ảnh nào, nó vẫn đang được tạo ra. Đây là vấn đề.

thứ hai trông như thế này

IProjectable projectable2 = element as IProjectable; 
if (projectable2 != null) 
{ 
    projectable2.SetView(...); 
} 

này đi ra như false cũng bởi vì các yếu tố, mà là một ContentPresenter, không thực hiện IProjectable. Điều này được thực hiện bởi đứa trẻ MapShapeBase và một lần nữa, đứa trẻ này chưa được tạo.

Vì vậy, SetView không bao giờ được gọi và _NormalizedMercatorToViewport trong MapShapeBase sẽ có giá trị mặc định của nó và lần đầu tiên bạn thêm một mục mới là sai.


Cách giải quyết

Để workaround vấn đề này chúng ta cần phải buộc một tái thước đo MapLayer. Điều này phải được thực hiện khi một ContentPresenter mới được thêm vào MapItemsControl nhưng sau khi số ContentPresenter có con trực quan.

Một cách để bắt buộc cập nhật là tạo thuộc tính đính kèm có cờ siêu dữ liệu AffectsRender, AffectsArrangeAffectsMeasure được đặt thành true. Sau đó, chúng tôi chỉ thay đổi giá trị của thuộc tính này mọi lúc chúng tôi muốn thực hiện cập nhật.

Đây là hành vi được đính kèm thực hiện việc này. Sử dụng nó như thế này

<m:Map ...> 
    <m:MapItemsControl Name="x" 
         behaviors:MapFixBehavior.FixUpdate="True"/> 
</m:Map> 

MapFixBehavior

public class MapFixBehavior 
{ 
    public static DependencyProperty FixUpdateProperty = 
     DependencyProperty.RegisterAttached("FixUpdate", 
              typeof(bool), 
              typeof(MapFixBehavior), 
              new FrameworkPropertyMetadata(false, 
                      OnFixUpdateChanged)); 

    public static bool GetFixUpdate(DependencyObject mapItemsControl) 
    { 
     return (bool)mapItemsControl.GetValue(FixUpdateProperty); 
    } 
    public static void SetFixUpdate(DependencyObject mapItemsControl, bool value) 
    { 
     mapItemsControl.SetValue(FixUpdateProperty, value); 
    } 

    private static void OnFixUpdateChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) 
    { 
     MapItemsControl mapItemsControl = target as MapItemsControl; 
     ItemsChangedEventHandler itemsChangedEventHandler = null; 
     itemsChangedEventHandler = (object sender, ItemsChangedEventArgs ea) => 
     { 
      if (ea.Action == NotifyCollectionChangedAction.Add) 
      { 
       EventHandler statusChanged = null; 
       statusChanged = new EventHandler(delegate 
       { 
        if (mapItemsControl.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) 
        { 
         mapItemsControl.ItemContainerGenerator.StatusChanged -= statusChanged; 
         int index = ea.Position.Index + ea.Position.Offset; 
         ContentPresenter contentPresenter = 
          mapItemsControl.ItemContainerGenerator.ContainerFromIndex(index) as ContentPresenter; 
         if (VisualTreeHelper.GetChildrenCount(contentPresenter) == 1) 
         { 
          MapLayer mapLayer = GetVisualParent<MapLayer>(mapItemsControl); 
          mapLayer.ForceMeasure(); 
         } 
         else 
         { 
          EventHandler layoutUpdated = null; 
          layoutUpdated = new EventHandler(delegate 
          { 
           if (VisualTreeHelper.GetChildrenCount(contentPresenter) == 1) 
           { 
            contentPresenter.LayoutUpdated -= layoutUpdated; 
            MapLayer mapLayer = GetVisualParent<MapLayer>(mapItemsControl); 
            mapLayer.ForceMeasure(); 
           } 
          }); 
          contentPresenter.LayoutUpdated += layoutUpdated; 
         } 
        } 
       }); 
       mapItemsControl.ItemContainerGenerator.StatusChanged += statusChanged; 
      } 
     }; 
     mapItemsControl.ItemContainerGenerator.ItemsChanged += itemsChangedEventHandler; 
    } 

    private static T GetVisualParent<T>(object childObject) where T : Visual 
    { 
     DependencyObject child = childObject as DependencyObject; 
     while ((child != null) && !(child is T)) 
     { 
      child = VisualTreeHelper.GetParent(child); 
     } 
     return child as T; 
    } 
} 

MapLayerExtensions

public static class MapLayerExtensions 
{ 
    private static DependencyProperty ForceMeasureProperty = 
     DependencyProperty.RegisterAttached("ForceMeasure", 
              typeof(int), 
              typeof(MapLayerExtensions), 
              new FrameworkPropertyMetadata(0, 
               FrameworkPropertyMetadataOptions.AffectsRender | 
               FrameworkPropertyMetadataOptions.AffectsArrange | 
               FrameworkPropertyMetadataOptions.AffectsMeasure)); 

    private static int GetForceMeasure(DependencyObject mapLayer) 
    { 
     return (int)mapLayer.GetValue(ForceMeasureProperty); 
    } 
    private static void SetForceMeasure(DependencyObject mapLayer, int value) 
    { 
     mapLayer.SetValue(ForceMeasureProperty, value); 
    } 

    public static void ForceMeasure(this MapLayer mapLayer) 
    { 
     SetForceMeasure(mapLayer, GetForceMeasure(mapLayer) + 1); 
    } 
} 
+0

@ChristiaanV: Bất kỳ may mắn nào với cách giải quyết mà tôi đề xuất? Nếu bạn có bất kỳ câu hỏi nào liên quan đến "lỗi", tôi rất vui Để thử và trả lời theo cách tôi thấy, vấn đề không phải với việc triển khai của bạn, nhưng với việc thực hiện 'Bản đồ' từ Microsoft. Tôi nghĩ rằng đây là một vấn đề cần phải được khắc phục khi kết thúc và cách duy nhất Để làm cho nó hoạt động cho đến khi họ làm là sử dụng một số loại workaround –

+0

Wow, đó là một câu trả lời tuyệt vời! Thực sự hạnh phúc với điều đó! – ChristiaanV

+0

Tôi đã tìm kiếm một sửa chữa cho vấn đề này một thời gian và trong khi đã có nhiều gợi ý này là duy nhất mà (cho đến nay) đã làm việc đáng tin cậy.Một điều mặc dù, có lẽ tôi đang cấu trúc XAML của tôi không chính xác nhưng nếu bạn đặt MapItemsControl bên trong một MapLayer sau đó sửa chữa không hoạt động.Cảm ơn tôi không rea Tôi cần nhiều lớp cho những gì tôi đang làm. –

Các vấn đề liên quan