У меня есть лишенный WPF-пример проблемы, с которой я сталкиваюсь в гораздо большем проекте. У меня есть пользовательский элемент управления UserControl1. Контекст данных установлен в self, поэтому у меня есть свойства зависимостей, определенные в коде.Пользовательский элемент управления WPF не обновляет путь
У меня есть элемент управления ItemsControl. В ItemsSource у меня есть CompositeCollection, который содержит CollectionContainer и строку. Линия только для того, чтобы доказать себе, что я рисую.
У меня также есть объект, называемый GraphPen, который содержит свойство зависимостей PathGeometry. Элемент CollectionContainer пользовательского элемента управления содержит ObservableCollection из этих GraphPens.
Теперь у меня есть «MainWindow», чтобы проверить пользовательский элемент управления. В MainWindow у меня есть DispatchTimer и в событии Tick этого таймера, я добавляю LineSegments к PathFigure, который был добавлен в коллекцию FigureG PathMeometry одного экземпляра GraphPen.
Я ожидаю увидеть диагональную линию, проходящую параллельно существующей красной линии, но ничего не появляется. Если я положил точку прерывания в конец обработчика событий Tick, я могу проверить пользовательский элемент управления и развернуться и увидеть, что сегменты линий существуют. По какой-то причине они не оказываются. Я подозреваю, что я сделал что-то неправильно в привязке.
Я поставлю код ниже.
GraphPen.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
namespace WpfExampleControlLibrary
{
public class GraphPen : DependencyObject
{
#region Constructor
public GraphPen()
{
PenGeometry = new PathGeometry();
}
#endregion Constructor
#region Dependency Properties
// Line Color
public static PropertyMetadata PenLineColorPropertyMetadata
= new PropertyMetadata(null);
public static DependencyProperty PenLineColorProperty
= DependencyProperty.Register(
"PenLineColor",
typeof(Brush),
typeof(GraphPen),
PenLineColorPropertyMetadata);
public Brush PenLineColor
{
get { return (Brush)GetValue(PenLineColorProperty); }
set { SetValue(PenLineColorProperty, value); }
}
// Line Thickness
public static PropertyMetadata PenLineThicknessPropertyMetadata
= new PropertyMetadata(null);
public static DependencyProperty PenLineThicknessProperty
= DependencyProperty.Register(
"PenLineThickness",
typeof(Int32),
typeof(GraphPen),
PenLineThicknessPropertyMetadata);
public Int32 PenLineThickness
{
get { return (Int32)GetValue(PenLineThicknessProperty); }
set { SetValue(PenLineThicknessProperty, value); }
}
// Pen Geometry
public static PropertyMetadata PenGeometryMetadata = new PropertyMetadata(null);
public static DependencyProperty PenGeometryProperty
= DependencyProperty.Register(
"PenGeometry",
typeof(PathGeometry),
typeof(UserControl1),
PenGeometryMetadata);
public PathGeometry PenGeometry
{
get { return (PathGeometry)GetValue(PenGeometryProperty); }
set { SetValue(PenGeometryProperty, value); }
}
#endregion Dependency Properties
}
}
UserControl1.xaml
<UserControl Name="ExampleControl"
x:Class="WpfExampleControlLibrary.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfExampleControlLibrary"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<DataTemplate DataType="{x:Type local:GraphPen}">
<Path Stroke="{Binding Path=PenLineColor}"
StrokeThickness="{Binding Path=PenLineThickness}"
Data="{Binding Path=Geometry}">
</Path>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<ItemsControl Grid.Column="0" Grid.Row="0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Aquamarine">
<Canvas.LayoutTransform>
<ScaleTransform ScaleX="1" ScaleY="-1" CenterX=".5" CenterY=".5"/>
</Canvas.LayoutTransform>
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemsSource>
<CompositeCollection>
<CollectionContainer
Collection="{
Binding Source={RelativeSource Self},
Path=GraphPens,
Mode=OneWay}"/>
<Line X1="10" Y1="0" X2="200" Y2="180" Stroke="DarkRed" StrokeThickness="2"/>
</CompositeCollection>
</ItemsControl.ItemsSource>
</ItemsControl>
<TextBox x:Name="debug" Grid.Column="0" Grid.Row="1" Text="{Binding Path=DebugText}"/>
</Grid>
</UserControl>
UserControl1.xaml.cs
namespace WpfExampleControlLibrary
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
GraphPens = new ObservableCollection<GraphPen>();
}
#region Dependency Properties
// Pens
public static PropertyMetadata GraphPenMetadata = new PropertyMetadata(null);
public static DependencyProperty GraphPensProperty
= DependencyProperty.Register(
"GraphPens",
typeof(ObservableCollection<GraphPen>),
typeof(UserControl1),
GraphPenMetadata);
public ObservableCollection<GraphPen> GraphPens
{
get { return (ObservableCollection<GraphPen>)GetValue(GraphPensProperty); }
set { SetValue(GraphPensProperty, value); }
}
// Debug Text
public static PropertyMetadata DebugTextMetadata = new PropertyMetadata(null);
public static DependencyProperty DebugTextProperty
= DependencyProperty.Register(
"DebugText",
typeof(string),
typeof(UserControl1),
DebugTextMetadata);
public string DebugText
{
get { return (string)GetValue(DebugTextProperty); }
set { SetValue(DebugTextProperty, value); }
}
#endregion Dependency Properties
}
}
MainWindow.xaml
<Window x:Class="POC_WPF_UserControlExample.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:Exmpl="clr-namespace:WpfExampleControlLibrary;assembly=WpfExampleControlLibrary"
xmlns:local="clr-namespace:POC_WPF_UserControlExample"
mc:Ignorable="d"
Title="MainWindow" Height="550" Width="550">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition />
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Exmpl:UserControl1 Grid.Column="1" Grid.Row="1" x:Name="myExample"/>
</Grid>
</Window>
MainWindow.xaml.cs
namespace POC_WPF_UserControlExample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private DispatcherTimer _timer = null;
private GraphPen _graphPen0 = null;
private Int32 _pos = 0;
private PathFigure _pathFigure = null;
public MainWindow()
{
InitializeComponent();
_graphPen0 = new GraphPen();
_graphPen0.PenLineColor = Brushes.DarkGoldenrod;
_graphPen0.PenLineThickness = 2;
myExample.GraphPens.Add(_graphPen0);
_timer = new DispatcherTimer();
_timer.Tick += Timer_Tick;
_timer.Interval = new TimeSpan(0, 0, 0, 0, 100);
_timer.Start();
}
private void Timer_Tick(object sender, EventArgs e)
{
_pos++;
Point penPoint0 = new Point(_pos, _pos + 20);
if (_graphPen0.PenGeometry.Figures.Count == 0)
{
_pathFigure = new PathFigure();
_graphPen0.PenGeometry.Figures.Add(_pathFigure);
_pathFigure.StartPoint = penPoint0;
}
else
{
LineSegment segment = new LineSegment(penPoint0, false);
_pathFigure.Segments.Add(segment);
}
myExample.DebugText = _pos.ToString();
}
}
}
Screen Shot
ли вы попробуйте заменить GraphPen вместо изменения существующего? –
Эд, спасибо за быстрый ответ. Просто попробовал, но радости. В каком-то смысле я рад, что это был не ответ. В большом проекте у меня будет десяток ручек, обновляющих их строки примерно раз в 10 миллисекунд. Я бы ненавидел накладные расходы, связанные с необходимостью воссоздавать ручки каждый раз. Я бы подумал, что ObservableCollection позаботится об этом для меня. – dtaylor
ObservableCollection вызывает события, когда вы добавляете или удаляете из него элементы. Он не знает, что происходит в свойствах элементов, которые он содержит. Ключевыми здесь являются ['_graphPen0.PenGeometry.Figures.Add (_pathFigure);'] (https://msdn.microsoft.com/en-us/library/system.windows.media.pathfigurecollection (v = vs.110) .aspx) и ['_pathFigure.Segments.Add (сегмент);'] (https://msdn.microsoft.com/en-us/library/system.windows.media.pathsegmentcollection (v = vs.110). ASPX). Я не думаю, что ни одна из этих коллекций не поднимает никаких событий, когда вы меняете их содержимое. –