我已经将我的视图从简单的画布改为使用画布的ItemsControl,因为我希望将Canvas子组件绑定到我的ViewModel。
是这样的:
<Canvas x:Name="worksheetCanvas">
<local:BlockControl DataContext="{Binding x}"/>
<local:BlockControl DataContext="{Binding y}"/>
<local:BlockControl DataContext="{Binding z}"/>
</Canvas>我向MVVM“移动”了一步,现在我有了以下内容:
<ItemsControl x:Name="itemsControl" ItemsSource="{Binding Blocks}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas x:Name="worksheetCanvas">
<!-- Here I have some attached properties defined -->
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Top" Value="{Binding BlockTop}"/>
<Setter Property="Canvas.Left" Value="{Binding BlockLeft}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:BlockControl/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>我必须从后面的代码中访问Canvas (我不想要纯MVVM,后面会有一些代码)。我在x:Name中为画布设置了ItemsPanelTemplate属性,但它不起作用:
错误CS0103名称'worksheetCanvas‘在当前上下文中不存在
我想这是因为画布是在编译后创建的,不能像这样访问。
在这个场景中,获得画布引用的最佳(有效)方法是什么?
发布于 2022-08-24 06:06:24
您可以创建派生的ItemsControl (作为WPF自定义控件),将画布作为项宿主,并创建一个使画布可访问的属性。
public class CanvasItemsControl : ItemsControl
{
static CanvasItemsControl()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(CanvasItemsControl),
new FrameworkPropertyMetadata(typeof(CanvasItemsControl)));
}
public Canvas Canvas { get; private set; }
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Canvas = Template.FindName("Canvas", this) as Canvas;
}
}像这样访问画布使用Themes/Generic.xaml中的默认样式,如下所示。它没有设置ItemsPanel属性,而是直接将宿主画布放入ItemsControl的ControlTemplate中。
<Style TargetType="{x:Type local:CanvasItemsControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ItemsControl">
<Canvas x:Name="Canvas" IsItemsHost="True"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>然后,您的XAML将如下所示:
<local:CanvasItemsControl x:Name="itemsControl" ItemsSource="{Binding Blocks}">
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Top" Value="{Binding BlockTop}"/>
<Setter Property="Canvas.Left" Value="{Binding BlockLeft}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:BlockControl/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</local:CanvasItemsControl>一旦应用了模板,您就可以访问Canvas属性,例如在窗口的加载事件处理程序中:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
itemsControl.Canvas.Background = Brushes.AliceBlue;
}发布于 2022-08-24 12:24:15
一旦加载了VisualTreeHelper类,您就可以使用ItemsControl类在可视树中找到ItemsControl,例如:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Canvas worksheetCanvas = FindVisualChild<Canvas>(itemsControl);
//...
}
private static childItem FindVisualChild<childItem>(DependencyObject obj)
where childItem : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is childItem)
{
return (childItem)child;
}
else
{
childItem childOfChild = FindVisualChild<childItem>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
}发布于 2022-08-23 23:04:32
您可以创建UserControl包装器。然后通过Content属性访问画布。
<ItemsPanelTemplate>
<local:MyCanvasWrapper>
<Canvas x:Name="worksheetCanvas">
<!-- Here I have some attached properties defined -->
</Canvas>
</local:MyCanvasWrapper>
</ItemsPanelTemplate>代码背后
public partial class MyCanvasWrapper : UserControl // Or ContentControl
{
public MyCanvasWrapper()
{
InitializeComponent();
Loaded += (s, e) => {
var canvas = Content as Canvas;
}
}
}https://stackoverflow.com/questions/73465458
复制相似问题