【问题标题】:Binding Silverlight controls collection to Grid - possible or not?将 Silverlight 控件集合绑定到 Grid - 可能与否?
【发布时间】:2012-11-27 06:35:21
【问题描述】:

我对 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}" />

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

【问题讨论】:

    标签: silverlight mvvm binding


    【解决方案1】:

    我认为可以为此使用 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 的“文本”属性中显示了“模型”属性(我已将其定义为“字符串”)。您可以将“模型”属性分配给控件的“DataContext”属性,如您的示例所示。

    希望对你有帮助!

    【讨论】:

    • 非常感谢您的回答,但是silverlight中一定有一些不同。例如,在 Canvas 中缺少 ItemPanelTemplate 属性 IsItemsHost,对于 ItemsControl.ItemContainerStyle (在 ItemsControl 中根本没有 ItemContainerStyle 属性)。我试图删除丢失的代码,但它不起作用 - 我的 ItemsControl 只显示一个控件。我还尝试只编写 ItemTemplate 部分,并让所有项目垂直对齐,就像它们在 StackPanel 中一样。
    【解决方案2】:

    所以,在谷歌搜索、询问和阅读之后,我找到了一个解决方案:

    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>
      

    像魅力一样工作 :) 谢谢大家。

    【讨论】:

      猜你喜欢
      • 2011-07-11
      • 2011-04-07
      • 2011-04-25
      • 2011-11-16
      • 1970-01-01
      • 2011-11-17
      • 1970-01-01
      • 1970-01-01
      • 2011-01-02
      相关资源
      最近更新 更多