Windows Phone-如何在动态创建的画布中绘制形状-XAML与代码隐藏

本文关键字:绘制 -XAML 隐藏 代码 布中 Phone- 动态 创建 Windows | 更新日期: 2023-09-27 18:19:29

我有一个longListSelector,它可以动态创建多个画布,我想使用ObservableCollection Games中的数据在每个画布中绘制。这是我主页的基本代码:

<Grid x:Name="ContentPanel">
  <phone:LongListSelector Name="myLLS" ItemSource="{Binding GamesVM}">
    <phone:LongListSelector.ItemTemplate>
      <DataTemplate>
        <StackPanel>
          <Canvas />  <!-- Here I want to draw -->    
          <TextBlock Text="{Binding Title}"/>
        </StackPanel>
      </DataTemplate>
    </phone:LongListSelector.ItemTemplate>
  </phone:LongListSelector>
</Grid>
public class GameVM : INotifyPropertyChanged {
  private string _title;     
  public string Title {
    get { return this._title; }
    set {
      if (this._title!= value) {
        this._title= value;
        this.OnPropertyChanged("Title");
      }
    }
  }
  public void Draw() {
    Ellispe stone = new Ellipse();
    // [...] Add Fill, Strock, Width, Height properties and set Canvas.Left and Canvas.Top...
    myCanvas.Children.Add(stone);
  }
}

我想在生成GamesVM集合时执行我的Draw方法,但此时我还没有访问相应的画布。把我的Draw方法放在代码后面并没有帮助,因为我没有事件可以处理,在那里我可以同时获得数据绑定对象和新生成的画布(除非我错过了什么…)。所以我在Draw方法中没有"myCanvas"实例。

我有一些想法要做,但没有什么好的。

选项1

我可以将我的UIElement(Ellipse、Line等)放在ObservableCollection中,该集合绑定在ItemsControl中,如下所示:

<ItemsControl ItemsSource="{Binding myUIElements}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <Canvas />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
</ItemsControl>
  public void Draw() {
    myUIElements = new ObservableCollection<UIElement>();
    Ellispe stone = new Ellipse();
    // [...] Add Fill, Strock, Width, Height properties and set Canvas.Left and Canvas.Top...
    myUIElements.Add(stone);
  }

它有效,但当我离开页面返回时,我得到一个元素。它已经是另一个元素的子元素异常。如果我使用VisualTreeHelper找到我的ItemsControl并对其调用Items.Clear(),我也会得到一个异常,因为Items是只读的。

选项2

我可以使用ContentControl而不是ItemsControl,并在我的Draw方法中创建画布:

<ContentControl Content="{Binding myUICanvas"/>
  public void Draw() {
    myUICanvas = new Canvas();
    Ellispe stone = new Ellipse();
    // [...] Add Fill, Strock, Width, Height properties and set Canvas.Left and Canvas.Top...
    myUICanvas.Children.Add(stone);
  }

它也起作用,但当我离开页面返回时,我会得到一个值不在预期范围内的异常。我知道我无法绑定UIElement,因为当框架再次尝试设置它们时,我无法清除它们。说"请不要两次添加相同的元素"有什么诀窍?

选项3

我可以尝试直接在XAML中绘制,并绑定ViewModel对象而不是UIElement对象。

<ItemsControl ItemsSource="{Binding myDatas}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <Canvas />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Ellipse Width="{Binding Diameter}" Fill="Black" ...>
      </Ellipse>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

它可以在WPF中工作,但在我的Windows Phone 8应用程序中,我没有ItemContainerStyle属性来设置Canvas。Left和Canvas.Right。此外,我必须使用CompositeCollection来处理几种形状,但Visual Studio无法识别DataType。此外,即使使用Line UIElements,渲染也比c#方法慢。

那么,什么是最好的选择?如何处理我的例外情况?

Windows Phone-如何在动态创建的画布中绘制形状-XAML与代码隐藏

有关信息,我会告诉您我选择哪一个。

我选择选项2,并通过每次重新绘制一个新画布来避免返回错误。我更改了Draw定义,这样它就会返回新的Canvas。

public class GameVM : INotifyPropertyChanged {
  // Title and other properties
  private Canvas _myUICanvas;
  public Canvas myUICanvas
  {
    get {
      _myUICanvas = Draw();
      return _myUICanvas;
    }
    set {
      // this is never called
      _myUICanvas = value;
    }
  }
  public Canvas Draw() {
    Canvas newCanvas = new Canvas();
    Ellispe stone = new Ellipse();
    // [...] Add Fill, Strock, Width, Height properties and set Canvas.Left and Canvas.Top...
    newCanvas.Children.Add(stone);
    return newCanvas;
  }
}

像这样,我可以在没有错误的情况下运行我的程序,而无需重新加载/创建所有的GameVM实例。