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#方法慢。
那么,什么是最好的选择?如何处理我的例外情况?
有关信息,我会告诉您我选择哪一个。
我选择选项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实例。