我如何在SilverLight中组合一些用户控件

本文关键字:合一 用户 控件 组合 SilverLight | 更新日期: 2023-09-27 18:09:47

也许这是一个简单的问题,但我找不到答案。我有三个用户控件,它们只有颜色不同。其中有一个代码:

<UserControl x:Class="SilverlightApplication14.NodePicture"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:SilverlightApplication14">
    <UserControl.Resources>
        <local:NodeViewModel x:Key="Children"  />
    </UserControl.Resources>
    <Grid x:Name="LayoutRootNodePicture" Height="100" Width="100"
          HorizontalAlignment="Center"  DataContext="{Binding Source={StaticResource Children}, Path=Children}" >
        <Canvas x:Name="ParentCanvas" Background="White" Width="100" Height="100" >
            <Rectangle Fill="Yellow" Stroke="Blue" Width="100" Height="100"   >
                </Rectangle  >
        </Canvas>
        <Image HorizontalAlignment="Center"
                       Source="add.png"
                       Stretch="Fill"
                       Width="16"
                       VerticalAlignment="Top"
                       Margin="0,0,2,2"
                       Height="16" MouseLeftButtonDown="Image_MouseLeftButtonDown">
        </Image>
            </Grid>
</UserControl>

如何将它们合并到ObservableCollection Children中?

public class NodeViewModel : INotifyPropertyChanged
    {
public ObservableCollection<NodeViewModel> Children
        {
            get { return _children; }
            set
            {
                _children = value;
                NotifyChange("Children");
            }
        }
        private void NotifyChange(string propName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
}

我如何使用这个控件集合的元素?

是否有一种简单的(或正确的)方法来做到这一点?

我如何在SilverLight中组合一些用户控件

据我所知,您有3个用户控件,其名称如NodePicture, GreenNodePicture和BlueNodePicture。首先,如果这3个控件差别很小,最好只有一个控件使用一些属性值来切换颜色。

让我们假设您的控件因画布上矩形的背景颜色而不同。所以我将改变你的控制,所以:

<Grid x:Name="LayoutRootNodePicture" Height="100" Width="100"
      HorizontalAlignment="Center">
    <Canvas x:Name="ParentCanvas" Background="{Binding NodeColor}" Width="100" Height="100" >
    </Canvas>
    <Image HorizontalAlignment="Center"
                   Source="add.png"
                   Stretch="Fill"
                   Width="16"
                   VerticalAlignment="Top"
                   Margin="0,0,2,2"
                   Height="16" MouseLeftButtonDown="Image_MouseLeftButtonDown">
    </Image>
</Grid>

我已经删除了Resources部分,因为视图不应该创建新的视图模型对象,它应该使用现有的DataContext。您可以看到,矩形的背景颜色是基于视图模型的属性NodeColor。让我们将这个属性添加到视图模型中:

public class NodeViewModel : INotifyPropertyChanged
{
    private SolidColorBrush _nodeColor;
    public SolidColorBrush NodeColor
    {
        get { return _nodeColor; }
        set
        {
            _nodeColor = value;
            NotifyChange("NodeColor");
        }
    }
    //...

现在如果你想用不同的颜色显示3个控件你应该用不同的属性创建3个视图模型。下面是红色、蓝色和绿色视图模型的示例:

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();
        var redBrush = new SolidColorBrush(Color.FromArgb(255, 255, 0, 0));
        var greenBrush = new SolidColorBrush(Color.FromArgb(255, 0, 255, 0));
        var blueBrush = new SolidColorBrush(Color.FromArgb(255, 0, 0, 255));
        this.DataContext = new MainViewModel
        {
            Nodes = new ObservableCollection<NodeViewModel>{
                new NodeViewModel 
                { 
                    NodeColor = redBrush,
                    Children = new ObservableCollection<NodeViewModel>{
                        new NodeViewModel { NodeColor = greenBrush, LeftOffset = 65, TopOffset = 10},
                        new NodeViewModel { NodeColor = greenBrush, LeftOffset = 55, TopOffset = 60}
                    }
                }, //red
                new NodeViewModel { NodeColor = greenBrush}, //green
                new NodeViewModel { NodeColor = blueBrush} //blue
            }
        };
    }
}
public class MainViewModel
{
    public ObservableCollection<NodeViewModel> Nodes { get; set; }
}

使用数据模板将视图模型转换为视图:

<ListBox ItemsSource="{Binding Nodes}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <local:NodePicture DataContext="{Binding}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

我没有使用Children属性,因为我不知道在哪里使用它。也许子节点显示在画布上。无论如何,如果它是重要的-你可以提供额外的信息,我会帮助这个。

更新:

在画布上绘制子项最简单的方法是添加依赖属性,当集合更新时,该属性会更新画布:

public partial class NodePicture : UserControl
{
    public NodePicture()
    {
        InitializeComponent();
    }
    public IEnumerable<NodeViewModel> ChildViewModels
    {
        get { return (IEnumerable<NodeViewModel>)GetValue(ChildViewModelsProperty); }
        set { SetValue(ChildViewModelsProperty, value); }
    }
    public static readonly DependencyProperty ChildViewModelsProperty =
        DependencyProperty.Register("ChildViewModels", typeof(IEnumerable<NodeViewModel>), typeof(NodePicture),
        new PropertyMetadata(null, (s, e) => ((NodePicture)s).UpdateCanvas()));
    private void UpdateCanvas()
    {
        this.ParentCanvas.Children.Clear();
        var items = this.ChildViewModels;
        if(items == null)
            return;
        var controls = items.Select(item=>
            {
                var e = new Ellipse{Width = 20, Height = 20};
                e.Fill = item.NodeColor;
                //Or using the data binding
                //BindingOperations.SetBinding(e, Ellipse.FillProperty, new Binding("NodeColor") { Source = item });
                Canvas.SetLeft(e, item.LeftOffset);
                Canvas.SetTop(e, item.TopOffset);
                return e;
            });
        foreach(var c in controls)
            this.ParentCanvas.Children.Add(c);
    }

其中的TopOffset和leftovers是NodeViewModel类的属性。之后,您应该在xaml代码中设置此属性:

    <DataTemplate>
        <local:NodePicture DataContext="{Binding}" ChildViewModels="{Binding Children}" />
    </DataTemplate>

它不会与ObservableColelction类工作,因为我没有处理CollectionChanged事件。另一种方法-将ListBox控件与自定义ItemsPanelTemplateListBoxItem ControlTemplate一起使用。但这是一个更复杂的解决方案。