首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在ItemsPanel中访问画布实例?

如何在ItemsPanel中访问画布实例?
EN

Stack Overflow用户
提问于 2022-08-23 22:01:24
回答 3查看 69关注 0票数 0

我已经将我的视图从简单的画布改为使用画布的ItemsControl,因为我希望将Canvas子组件绑定到我的ViewModel。

是这样的:

代码语言:javascript
复制
<Canvas x:Name="worksheetCanvas">   
    <local:BlockControl DataContext="{Binding x}"/>                         
    <local:BlockControl DataContext="{Binding y}"/>                         
    <local:BlockControl DataContext="{Binding z}"/>                         
</Canvas>

我向MVVM“移动”了一步,现在我有了以下内容:

代码语言:javascript
复制
<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‘在当前上下文中不存在

我想这是因为画布是在编译后创建的,不能像这样访问。

在这个场景中,获得画布引用的最佳(有效)方法是什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-08-24 06:06:24

您可以创建派生的ItemsControl (作为WPF自定义控件),将画布作为项宿主,并创建一个使画布可访问的属性。

代码语言:javascript
复制
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中。

代码语言:javascript
复制
<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将如下所示:

代码语言:javascript
复制
<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属性,例如在窗口的加载事件处理程序中:

代码语言:javascript
复制
private void Window_Loaded(object sender, RoutedEventArgs e)
{
    itemsControl.Canvas.Background = Brushes.AliceBlue;
}
票数 1
EN

Stack Overflow用户

发布于 2022-08-24 12:24:15

一旦加载了VisualTreeHelper类,您就可以使用ItemsControl类在可视树中找到ItemsControl,例如:

代码语言:javascript
复制
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;
    }
}
票数 1
EN

Stack Overflow用户

发布于 2022-08-23 23:04:32

您可以创建UserControl包装器。然后通过Content属性访问画布。

代码语言:javascript
复制
<ItemsPanelTemplate>
    <local:MyCanvasWrapper>
        <Canvas x:Name="worksheetCanvas">   
            <!-- Here I have some attached properties defined -->
        </Canvas>
    </local:MyCanvasWrapper>
</ItemsPanelTemplate>

代码背后

代码语言:javascript
复制
public partial class MyCanvasWrapper : UserControl // Or ContentControl
{
    public MyCanvasWrapper()
    {
        InitializeComponent();
        Loaded += (s, e) => {
            var canvas = Content as Canvas;
        }
    }
}
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73465458

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档