我对Silverlight有点新,现在我正在开发一个地图应用程序。我有一组自定义控件(地图标记,POI等)。每个控件都有一个Point类型的属性“Location”,其中Location.X
表示控件的Canvas.Left
,Location.Y
表示控件的Canvas.Top
。
我正在尝试将我的接口重构为MVVM模式。我想做这样的事情:
说我的控件在Canvas中。我希望有类似的东西:
<Canvas DataContext="{StaticResource myModel}" ItemsSource="{Binding controlsCollection}">
<Canvas.ItemTemplate> ... </Canvas.ItemTemplate>
</Canvas>
在我的自定义控件中,我希望有类似的内容:
<myCustomControl DataContext="{StaticResource myControlModel}" Canvas.Left="{Binding Location.X}" Canvas.Top="{Binding Location.Y}" />
有可能吗?也许有更好的方法?
答案 0 :(得分:0)
我认为可以使用ItemsControl控件。
假设你创建了一个持有者控件来保存控件的位置+你选择的更多信息。 我称之为“ControlDefinition.cs”:
public class ControlDefinition : DependencyObject, INotifyPropertyChanged
{
public static readonly DependencyProperty TopProperty = DependencyProperty.Register("Top", typeof(Double), typeof(ControlDefinition), new PropertyMetadata(0d));
public static readonly DependencyProperty LeftProperty = DependencyProperty.Register("Left", typeof(Double), typeof(ControlDefinition), new PropertyMetadata(0d));
public static readonly DependencyProperty ModelProperty = DependencyProperty.Register("Model", typeof(Object), typeof(ControlDefinition), new PropertyMetadata(null));
public Double Top
{
get { return (Double)GetValue(TopProperty); }
set
{
SetValue(TopProperty, value);
NotifyPropertyChanged("Top");
}
}
public Double Left
{
get { return (Double)GetValue(LeftProperty); }
set
{
SetValue(LeftProperty, value);
NotifyPropertyChanged("Left");
}
}
public Object Model
{
get { return (Object)GetValue(ModelProperty); }
set
{
SetValue(ModelProperty, value);
NotifyPropertyChanged("Model");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String aPropertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(aPropertyName));
}
}
然后,在我的MODEL(ViewModel.cs)中,我创建了这个类的ObservableCollection:
public static readonly DependencyProperty ControlsProperty = DependencyProperty.Register("Controls", typeof(ObservableCollection<ControlDefinition>), typeof(MainWindow), new PropertyMetadata(null));
public new ObservableCollection<ControlDefinition> Controls
{
get { return (ObservableCollection<ControlDefinition>)GetValue(ControlsProperty); }
set
{
SetValue(ControlsProperty, value);
NotifyPropertyChanged("Controls");
}
}
然后,在同一个MODEL中,我初始化集合并添加4个虚拟控件:
this.Controls = new ObservableCollection<ControlDefinition>();
this.Controls.Add(new ControlDefinition() { Top = 10, Left = 10, Model = "One" });
this.Controls.Add(new ControlDefinition() { Top = 50, Left = 10, Model = "Two" });
this.Controls.Add(new ControlDefinition() { Top = 90, Left = 10, Model = "Three" });
我的VIEW(View.xaml)就像这样:
<ItemsControl ItemsSource="{Binding Path=Controls}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Beige" IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Model, Mode=OneWay}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Top" Value="{Binding Path=Top, Mode=OneWay}" />
<Setter Property="Canvas.Left" Value="{Binding Path=Left, Mode=OneWay}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
请注意,我在“DataTemplate”中显示“TextBlock”控件,因为您无法控制。 我在TextBlock的“Text”属性中显示“Model”属性(我将其定义为“String”)。您可以将“Model”属性分配给控件的“DataContext”属性,如示例所示。
希望它有所帮助!
答案 1 :(得分:0)
所以,经过谷歌搜索,询问和阅读的所有时间,在这里我找到了一个解决方案:
应该有一个实现INotifyPropertyChanged接口的模型。 DependencyProperties不是必需的。这是一个例子:
public class MyItemModel: INotifyPropertyChanged
{
// INotifyPropertyChanged implementation
...
//
private Point _location;
public Point Location
{
get { return Location; }
set { _location = value; NotifyPropertyChanged("Location"); }
}
// any other fields
...
//
}
然后,假设我们有一个包含MyItemModels集合的模型:
public class MyModel: INotifyPropertyChanged
{
// INotifyPropertyChanged implementation
...
//
private ObservableCollection<MyItemModel> _myCollection;
public ObservableCollection<MyItemModel> MyCollection
{
get { return _myCollection; }
set { _myCollection = value; NotifyPropertyChanged("MyCollection"); }
}
}
然后,在XAML中,我们应该像这样使用ItemsControl:
<ItemsControl x:Name="LayoutRoot" DataContext="{StaticResource model}"
ItemsSource="{Binding MyCollection}"
HorizontalAlignment="Left" VerticalAlignment="Top">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas x:Name="host"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid x:Name="item" Background="Transparent">
<Grid.RenderTransform>
<TranslateTransform X="{Binding Location.X}" Y="{Binding Location.Y}"/>
</Grid.RenderTransform>
// other stuff here
...
//
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
像魅力一样工作:)谢谢大家。