我如何在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));
}
}
我如何使用这个控件集合的元素?
是否有一种简单的(或正确的)方法来做到这一点?
据我所知,您有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
控件与自定义ItemsPanelTemplate
和ListBoxItem ControlTemplate
一起使用。但这是一个更复杂的解决方案。