WPF - привязка не-коллекции элементов в CompositeCollection - PullRequest
0 голосов
/ 10 февраля 2020

Это вопрос типа «что я делаю неправильно». Я перевел свою проблему в простое приложение для проверки концепции. Я приведу код ниже.

В двух словах: у меня есть ItemsControl в ScrollViewer. В этом ItemsControl я хочу поместить несколько типов вещей. Я создаю CompositeCollection в ItemsControl.ItemSource для содержания. Для примера у меня есть коллекция объектов, каждый из которых является в основном меткой. У меня также есть строка, значения которой жестко закодированы. Наконец, у меня есть строка, конечные точки которой я хотел бы связать, чтобы я мог их динамически изменять.

CompositeCollection не имеет свойства DataContext, поскольку оно не является производным от FrameworkElement, поэтому операторы привязки должны включать источник , Для коллекции объектов я создал CollectionViewSource в ресурсах ItemsControl. Затем я ссылаюсь на это как на источник, когда связываю коллекцию объектов в CompositCollection. Это хорошо работает.

Жестко запрограммированная линия также хорошо работает, поэтому я знаю, что могу нарисовать линию.

Проблема заключается в связанной линии. Я попытался сослаться на источник напрямую, указав путь к нужным мне данным. Затем я попытался создать CollectionViewSource, как сделал для коллекции объектов. Ни один из них не работал. Я чувствую, что я рядом, просто что-то упускаю. Может кто-нибудь меня расклеит?

Даг

Код следующий:

MainWindow.xaml

<Window x:Class="POC_WPF_CompositeCollection_Binding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:POC_WPF_CompositeCollection_Binding"
        mc:Ignorable="d"
        Title="MainWindow" Height="500" Width="700">
    <Window.Resources>

        <local:MainWindowResource x:Key="MainWindowResource"/>

        <DataTemplate DataType="{x:Type local:NowLineArt}">
            <Line
                X1="{Binding AX, Mode=TwoWay}"
                Y1="{Binding AY, Mode=TwoWay}"
                X2="{Binding BX, Mode=TwoWay}"
                Y2="{Binding BY, Mode=TwoWay}"
                Stroke="Red"
                StrokeThickness="6">
            </Line>
        </DataTemplate>

        <DataTemplate DataType="{x:Type local:LoadIdArt}">
            <Canvas>
                <Label 
                    Canvas.Top="{Binding Top, Mode=TwoWay}" 
                    Content="{Binding Content, Mode=TwoWay}" 
                    Canvas.Left="5" 
                    Width="100" 
                    Height="25" 
                    Focusable="False" 
                    FontFamily="Arial" 
                    FontSize="16" 
                    FontWeight="Bold"
                    Foreground="Black">
                </Label>
            </Canvas>
        </DataTemplate>

    </Window.Resources>

    <ScrollViewer
        x:Name="scroller"
        HorizontalScrollBarVisibility="Visible"
        VerticalScrollBarVisibility="Visible"
        MouseMove="Scroller_MouseMove">
        <ItemsControl>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas 
                        x:Name="ContentCanvas" 
                        Background="Aquamarine"
                        Width="600"
                        Height="400">
                    </Canvas>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.Resources>
                <CollectionViewSource x:Key="LoadIdCollection" Source="{Binding LoadIdCol}"/>
                <CollectionViewSource x:Key="LineResource" Source="{Binding NowLine}"/>
            </ItemsControl.Resources>
            <ItemsControl.ItemsSource>
                <CompositeCollection>
                    <!--The CompositeCollection class does not derive from FrameworkElement
                    and thus does not have a DataContext property to support data
                    binding.  It will only work if you use Binding providing a Source.-->
                    <CollectionContainer Collection="{Binding Source={StaticResource LoadIdCollection}}"/>
                    <Line X1="0" Y1="0" X2="600" Y2="400" Stroke="Green" StrokeThickness="6"/>
                    <!--<Line X1="{Binding Source={StaticResource MainWindowResource}, Path=NowLine.AX}"
                            Y1="{Binding Source={StaticResource MainWindowResource}, Path=NowLine.AY}"
                            X2="{Binding Source={StaticResource MainWindowResource}, Path=NowLine.BX}"
                            Y2="{Binding Source={StaticResource MainWindowResource}, Path=NowLine.BY}"
                            Stroke="Red" StrokeThickness="6"/>-->
                    <Line X1="{Binding Source={StaticResource LineResource}, Path=AX}"
                            Y1="{Binding Source={StaticResource LineResource}, Path=AY}"
                            X2="{Binding Source={StaticResource LineResource}, Path=BX}"
                            Y2="{Binding Source={StaticResource LineResource}, Path=BY}"
                            Stroke="Red" StrokeThickness="6"/>
                </CompositeCollection>
            </ItemsControl.ItemsSource>
        </ItemsControl>
    </ScrollViewer>
</Window>

MainWindow.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace POC_WPF_CompositeCollection_Binding
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private MainWindowResource _resource = null;
        private Point _mouseInScroll = new Point(0.0, 0.0);

        public MainWindow()
        {
            LoadIdArt loadIdArt = null;
            NowLineArt nowLineArt = null;

            InitializeComponent();

            // get a reference to the binding sources so we can set the properties
            _resource = new MainWindowResource();
            this.DataContext = _resource;

            loadIdArt = new LoadIdArt(40, "First");
            _resource.LoadIdCol.Add(loadIdArt);
            loadIdArt = new LoadIdArt(80, "Second");
            _resource.LoadIdCol.Add(loadIdArt);
            loadIdArt = new LoadIdArt(120, "Third");
            _resource.LoadIdCol.Add(loadIdArt);

            nowLineArt = new NowLineArt(600, 0, 0, 400);
            _resource.NowLine = nowLineArt;
        }

        private void Scroller_MouseMove(object sender, MouseEventArgs e)
        {
            ScrollViewer scrollViewer = sender as ScrollViewer;
            // if the mouse is over the scrollviewer...
            if (scrollViewer.IsMouseOver)
            {
                // save the position
                _mouseInScroll = e.GetPosition(scrollViewer);
            }
        }
    }
}

MainWindowResource.cs

using System.Collections.ObjectModel;
using System.ComponentModel;

namespace POC_WPF_CompositeCollection_Binding
{
    class MainWindowResource : INotifyPropertyChanged
    {
        #region Private Members

        private ObservableCollection<LoadIdArt> _loadIdCol = null;
        private NowLineArt _nowLine = null;

        #endregion Private Members

        #region Constructor

        public MainWindowResource()
        {
            _loadIdCol = new ObservableCollection<LoadIdArt>();
            _nowLine = new NowLineArt();
        }

        #endregion Constructor

        #region Drawable Objects

        public ObservableCollection<LoadIdArt> LoadIdCol
        {
            get { return _loadIdCol; }
            set
            {
                _loadIdCol = value;
                OnPropertyChanged("LoadIdCol");
            }
        }

        public NowLineArt NowLine
        {
            get { return _nowLine; }
            set
            {
                _nowLine = value;
                OnPropertyChanged("NowLine");
            }
        }

        #endregion Drawable Objects

        #region PropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        // Create the OnPropertyChanged method to raise the event
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }

        #endregion PropertyChanged
    }
}

LoadIdArt.cs

using System.ComponentModel;

namespace POC_WPF_CompositeCollection_Binding
{
    class LoadIdArt : INotifyPropertyChanged
    {
        #region Constructors

        public LoadIdArt() { }

        public LoadIdArt(
            double top,
            string content
            )
        {
            Top = top;
            Content = content;
        }

        #endregion Constructors

        #region Depenency Properties

        /// <summary>
        /// Top
        /// </summary>
        private double _top = 0.0;
        public double Top
        {
            get { return _top; }
            set { _top = value; OnPropertyChanged("Top"); }
        }

        /// <summary>
        /// Content
        /// </summary>
        private string _content = "";
        public string Content
        {
            get { return _content; }
            set { _content = value; OnPropertyChanged("Content"); }
        }

        #endregion Depenency Properties

        #region PropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        // Create the OnPropertyChanged method to raise the event
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }

        #endregion PropertyChanged
    }
}

NowLineArt.cs

using System.ComponentModel;

namespace POC_WPF_CompositeCollection_Binding
{
    class NowLineArt : INotifyPropertyChanged
    {
        #region Constructors

        public NowLineArt() { }
        public NowLineArt(double ax, double ay, double bx, double by)
        {
            AX = ax;
            AY = ay;
            BX = bx;
            BY = by;
        }

        #endregion Constructors

        #region Dependency Properties

        // AX

        private double _ax = 0.0;
        public double AX
        {
            get { return _ax; }
            set { _ax = value; OnPropertyChanged("AX"); }
        }

        // AY

        private double _ay = 0.0;
        public double AY
        {
            get { return _ay; }
            set { _ay = value; OnPropertyChanged("AY"); }
        }

        // BX

        private double _bx = 0.0;
        public double BX
        {
            get { return _bx; }
            set { _bx = value; OnPropertyChanged("BX"); }
        }

        // BY

        private double _by = 0.0;
        public double BY
        {
            get { return _by; }
            set { _by = value; OnPropertyChanged("BY"); }
        }

        #endregion Dependency Properties

        #region PropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        // Create the OnPropertyChanged method to raise the event
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }

        #endregion PropertyChanged
    }
}
...