0

我对 Silverlight 有点陌生,现在我正在开发一个地图应用程序。我有一组自定义控件(地图标记、POI 等)。每个控件都有一个 Point 类型的属性“Location”,其中控件的Location.X意思是控件的意思。Canvas.LeftLocation.YCanvas.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}" />

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

4

2 回答 2

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));
    }
}

然后,在我的模型(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");
    }
}

然后,在同一个模型中,我初始化集合并添加 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”属性,如您的示例中所示。

希望能帮助到你!

于 2012-12-16T14:40:43.133 回答
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. 然后,假设我们有一个包含 MyItemModel 集合的模型:

    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>
    

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

于 2013-02-26T13:57:08.710 回答