绑定Silverlight控件集合到网格 - 可能与否?

时间:2012-11-27 06:35:21

标签: silverlight mvvm binding

我对Silverlight有点新,现在我正在开发一个地图应用程序。我有一组自定义控件(地图标记,POI等)。每个控件都有一个Point类型的属性“Location”,其中Location.X表示控件的Canvas.LeftLocation.Y表示控件的Canvas.Top

我正在尝试将我的接口重构为MVVM模式。我想做这样的事情:

  1. 说我的控件在Canvas中。我希望有类似的东西:

    <Canvas DataContext="{StaticResource myModel}" ItemsSource="{Binding controlsCollection}">

    <Canvas.ItemTemplate> ... </Canvas.ItemTemplate>

    </Canvas>

  2. 在我的自定义控件中,我希望有类似的内容:

    <myCustomControl DataContext="{StaticResource myControlModel}" Canvas.Left="{Binding Location.X}" Canvas.Top="{Binding Location.Y}" />

  3. 有可能吗?也许有更好的方法?

2 个答案:

答案 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)

所以,经过谷歌搜索,询问和阅读的所有时间,在这里我找到了一个解决方案:

  1. 应该有一个实现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
        ...
        //
    }
    
  2. 然后,假设我们有一个包含MyItemModels集合的模型:

    public class MyModel: INotifyPropertyChanged
    {
        // INotifyPropertyChanged implementation
        ...
        //
    
        private ObservableCollection<MyItemModel> _myCollection;
        public ObservableCollection<MyItemModel> MyCollection
        {
            get { return _myCollection; }
            set { _myCollection = value; NotifyPropertyChanged("MyCollection"); }
        }
    }
    
  3. 然后,在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>
    
  4. 像魅力一样工作:)谢谢大家。