Petr Ehler Ответов: 1

В WPF привязки пользовательского объекта inkcanvas


Привет,
Я пытаюсь привязать детскую коллекцию к пользовательским Чернильницам. В этот момент программа связывается с холстом к коду без проблем, но не с другой стороны.
Спасибо за помощь
Петр


Журнал Отладки:
The thread 0x2c88 has exited with code 259 (0x103).
'test_wpf.vshost.exe' (CLR v4.0.30319: test_wpf.vshost.exe): Loaded 'C:\Users\petr.ehler\Documents\Visual Studio 2013\Projects\test_wpf\test_wpf\bin\Debug\test_wpf.exe'. Symbols loaded.
'test_wpf.vshost.exe' (CLR v4.0.30319: test_wpf.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll'. Symbols loaded.
'test_wpf.vshost.exe' (CLR v4.0.30319: test_wpf.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.Aero\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.Aero.dll'. Symbols loaded.
System.Windows.Data Warning: 56 : Created BindingExpression (hash=22226817) for Binding (hash=54181020)
System.Windows.Data Warning: 58 :   Path: 'BorderItems'
System.Windows.Data Warning: 61 : BindingExpression (hash=22226817): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 62 : BindingExpression (hash=22226817): Attach to test_wpf.MyCanvas.Source (hash=46367191)
System.Windows.Data Warning: 67 : BindingExpression (hash=22226817): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=22226817): Found data context element: MyCanvas (hash=46367191) (OK)
System.Windows.Data Warning: 71 : BindingExpression (hash=22226817): DataContext is null
System.Windows.Data Warning: 65 : BindingExpression (hash=22226817): Resolve source deferred
System.Windows.Data Warning: 67 : BindingExpression (hash=22226817): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=22226817): Found data context element: MyCanvas (hash=46367191) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=22226817): Activate with root item MainWindow (hash=3528959)
System.Windows.Data Warning: 108 : BindingExpression (hash=22226817):   At level 0 - for MainWindow.BorderItems found accessor RuntimePropertyInfo(BorderItems)
System.Windows.Data Warning: 104 : BindingExpression (hash=22226817): Replace item at level 0 with MainWindow (hash=3528959), using accessor RuntimePropertyInfo(BorderItems)
System.Windows.Data Warning: 101 : BindingExpression (hash=22226817): GetValue at level 0 from MainWindow (hash=3528959) using RuntimePropertyInfo(BorderItems): ObservableCollection`1 (hash=55866471 Count=0)
System.Windows.Data Warning: 80 : BindingExpression (hash=22226817): TransferValue - got raw value ObservableCollection`1 (hash=55866471 Count=0)
System.Windows.Data Warning: 89 : BindingExpression (hash=22226817): TransferValue - using final value ObservableCollection`1 (hash=55866471 Count=0)
'test_wpf.vshost.exe' (CLR v4.0.30319: test_wpf.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemXmlLinq\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemXmlLinq.dll'. Symbols loaded.
'test_wpf.vshost.exe' (CLR v4.0.30319: test_wpf.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemXml\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemXml.dll'. Symbols loaded.
'test_wpf.vshost.exe' (CLR v4.0.30319: test_wpf.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationTypes\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationTypes.dll'. Symbols loaded.
System.Windows.Data Warning: 95 : BindingExpression (hash=22226817): Got PropertyChanged event from MainWindow (hash=3528959)
System.Windows.Data Warning: 101 : BindingExpression (hash=22226817): GetValue at level 0 from MainWindow (hash=3528959) using RuntimePropertyInfo(BorderItems): ObservableCollection`1 (hash=55866471 Count=1)
System.Windows.Data Warning: 80 : BindingExpression (hash=22226817): TransferValue - got raw value ObservableCollection`1 (hash=55866471 Count=1)
System.Windows.Data Warning: 89 : BindingExpression (hash=22226817): TransferValue - using final value ObservableCollection`1 (hash=55866471 Count=1)
'test_wpf.vshost.exe' (CLR v4.0.30319: test_wpf.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemData\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemData.dll'. Symbols loaded.
System.Windows.Data Warning: 95 : BindingExpression (hash=22226817): Got PropertyChanged event from MainWindow (hash=3528959)
System.Windows.Data Warning: 101 : BindingExpression (hash=22226817): GetValue at level 0 from MainWindow (hash=3528959) using RuntimePropertyInfo(BorderItems): ObservableCollection`1 (hash=55866471 Count=1)
System.Windows.Data Warning: 80 : BindingExpression (hash=22226817): TransferValue - got raw value ObservableCollection`1 (hash=55866471 Count=1)
System.Windows.Data Warning: 89 : BindingExpression (hash=22226817): TransferValue - using final value ObservableCollection`1 (hash=55866471 Count=1)
System.Windows.Data Warning: 95 : BindingExpression (hash=22226817): Got PropertyChanged event from MainWindow (hash=3528959)
System.Windows.Data Warning: 101 : BindingExpression (hash=22226817): GetValue at level 0 from MainWindow (hash=3528959) using RuntimePropertyInfo(BorderItems): ObservableCollection`1 (hash=55866471 Count=1)
System.Windows.Data Warning: 80 : BindingExpression (hash=22226817): TransferValue - got raw value ObservableCollection`1 (hash=55866471 Count=1)
System.Windows.Data Warning: 89 : BindingExpression (hash=22226817): TransferValue - using final value ObservableCollection`1 (hash=55866471 Count=1)
The thread 0x3784 has exited with code 259 (0x103).
The thread 0x3050 has exited with code 259 (0x103).
The program '[12308] test_wpf.vshost.exe' has exited with code 0 (0x0).


Что я уже пробовал:

основной класс
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;

namespace test_wpf
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public ObservableCollection<ItemDetail> BorderItems
        {
            get;
            set;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
            BorderItems = new ObservableCollection<ItemDetail>();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if(BorderItems.Count == 0)
            {
                return;
            }

            BorderItems[0].X = 200;
            BorderItems[0].Y = 300;
            BorderItems[0].Width = 200;
            BorderItems[0].Height = 100;

            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("BorderItems"));
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            ItemDetail d = new ItemDetail();
            d.X = 100;
            d.Y = 100;
            d.Width = 100;
            d.Height = 100;
            d.Type = "text";
            d.Text = "Test "+BorderItems.Count.ToString();

            BorderItems.Add(d);

            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("BorderItems"));
        }
    }
}


MyCanvas
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace test_wpf
{
    public class MyCanvas : InkCanvas
    {
        //Just a simple INotifyCollectionChanged collection
        public ObservableCollection<ItemDetail> Source { get; set; }

        public static readonly DependencyProperty SourceProperty =
            DependencyProperty.Register("Source",
            typeof(ObservableCollection<ItemDetail>),
            typeof(MyCanvas),
            new FrameworkPropertyMetadata(new ObservableCollection<ItemDetail>(),
            new PropertyChangedCallback(SourceChanged)));

        //called when a new value is set (through binding for example)
        protected static void SourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            //gets the instance that changed the "local" value
            var instance = sender as MyCanvas;
            //the new collection that will be set
            ObservableCollection<ItemDetail> newCollection = args.NewValue as ObservableCollection<ItemDetail>;
            //the previous collection that was set
            ObservableCollection<ItemDetail> oldCollection = args.OldValue as ObservableCollection<ItemDetail>;

            if (oldCollection != null)
            {
                //removes the CollectionChangedEventHandler from the old collection
                oldCollection.CollectionChanged -= new NotifyCollectionChangedEventHandler(instance.collection_CollectionChanged);
            }

            //clears all the previous children in the collection
            instance.Children.Clear();

            if (newCollection != null)
            {
                //adds all the children of the new collection
                foreach (ItemDetail item in newCollection)
                {
                    AddControl(item, instance);
                }

                //adds a new CollectionChangedEventHandler to the new collection
                newCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(instance.collection_CollectionChanged);

            }

        }


        //append when an Item in the collection is changed
        protected void collection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            //adds the new items in the children collection
            foreach (ItemDetail item in e.NewItems)
            {
                AddControl(item);
            }
        }


        protected static void AddControl(ItemDetail item, InkCanvas parentControl)
        {
            Border border = new Border();

            border.DataContext = item;
            border.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#000000"));

            border.Width = item.Width;
            border.Height = item.Height;

            
            if(item.Type == "text")
            {
                TextBlock tb = new TextBlock();
                tb.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFFFFF"));
                tb.FontSize = 25;
                tb.HorizontalAlignment = HorizontalAlignment.Center;
                tb.VerticalAlignment = VerticalAlignment.Center;
                Binding TextBinding = new Binding("Text");
                TextBinding.Source = item;
                TextBinding.Mode = BindingMode.TwoWay;

                tb.SetBinding(TextBlock.TextProperty, TextBinding);

                //tb.Text = item.Text;
                border.Child = tb;
            }
             

            parentControl.Children.Add(border);

            Binding XBinding = new Binding("X");
            XBinding.Source = item;
            XBinding.Mode = BindingMode.TwoWay;

            Binding YBinding = new Binding("Y");
            YBinding.Source = item;
            YBinding.Mode = BindingMode.TwoWay;

            border.SizeChanged += border_SizeChanged;

            border.SetBinding(InkCanvas.LeftProperty, XBinding);
            border.SetBinding(InkCanvas.TopProperty, YBinding);
        }

        private static void border_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Border border = sender as Border;
            if (border == null)
            {
                throw new ArgumentException("Unexpected object. Expected border");
            }
            var i = border.DataContext;
            ItemDetail itemDetail = i as ItemDetail;
            if (itemDetail == null)
            {
                throw new ArgumentException("Unexpected object. Expected ItemDetail");
            }
            itemDetail.Width = border.ActualWidth;
            itemDetail.Height = border.ActualHeight;
        }

        protected void AddControl(ItemDetail item)
        {
            AddControl(item, this);
        }


        static MyCanvas()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCanvas), new FrameworkPropertyMetadata(typeof(MyCanvas)));
        }

        public MyCanvas()
            : base()
        {

        }
    }
}


Деталь
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Controls;

namespace test_wpf
{
    
    public class ItemDetail: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public int X { get; set; }
        public int Y { get; set; }
        public double Width { get; set; }
        public double Height { get; set; }
        public string Type { get; set; }
        public string Text { get; set; }
    }
}


MainClassWPF
<Window x:Class="test_wpf.MainWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:src="clr-namespace:test_wpf"

    Title="InkCanvasElementSelection"

    ResizeMode="CanResize"

    xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"

    Height="800" Width="600">
    
    <DockPanel LastChildFill="True">
        <StackPanel DockPanel.Dock="Left" Width="200" Orientation="Vertical">
            <Line Margin="5"/>
            <TextBlock>Create new Element</TextBlock>
            <Button Click="Button_Click_1" Height="20" Content="New"/>
            <Line Margin="5"/>
            <TextBlock>Change Element 0</TextBlock>
            <Button Click="Button_Click" Height="20" Content="Change"/>
        </StackPanel>
        <src:MyCanvas Source="{Binding Path=BorderItems, Mode=TwoWay}" Background="AliceBlue" EditingMode="Select"/>
    </DockPanel>
</Window>

Richard Deeming

Проверьте окно "вывод" в Visual Studio на наличие ошибок привязки.

1 Ответов

Рейтинг:
8

Petr Ehler

Привет,
решение было довольно простым. Inkcanvas не знал об изменениях в классе ItemDetail. Класс ItemDetail не был заметен. Просто обновите класс, как

public class ItemDetail: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private int _x;
        private int _y;
        private double _width;
        private double _height;
        private string _type;
        private string _text;

        public int X {
            get { return _x; }
            set { _x = value; NotifyPropertyChanged("X"); }
        }

        public int Y
        {
            get { return _y; }
            set { _y = value; NotifyPropertyChanged("Y"); }
        }

        public double Width
        {
            get { return _width; }
            set { _width = value; NotifyPropertyChanged("Width"); }
        }

        public double Height
        {
            get { return _height; }
            set { _height = value; NotifyPropertyChanged("Height"); }
        }

        public string Type
        {
            get { return _type; }
            set { _type = value; NotifyPropertyChanged("Type"); }
        }
        public string Text
        {
            get { return _text; }
            set { _text = value; NotifyPropertyChanged("Text"); }
        }
        
    }


и код функциональный.

Петр