wpf 数据绑定自定义控件 - 为什么自定义控件未检测到对我的数据源的更改?
我有一个自定义控件和一个视图模型对象。视图模型上的属性绑定到自定义控件,我可以看到自定义控件实际上从视图模型对象接收值 - 但我的处理程序代码 (GeometryText.Set) 没有执行。我做错了什么?!
请注意自定义控件上的事件处理程序,我在其中放置了断点 - 如果我更改窗口的大小,我可以检查监视窗口中的 GeometryText 属性 - 并且它在我期望的情况下明显更新。
感谢您提供任何意见,
Anders,丹麦
ComponentDrawing.xaml.cs
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Rap1D.ServiceLayer.Interfaces.Services;
using StructureMap;
namespace Rap1D.Rap1D_WPF.Controls
{
/// <summary>
/// Interaction logic for ComponentDrawing.xaml
/// </summary>
public partial class ComponentDrawing
{
public static DependencyProperty GeometryTextProperty =DependencyProperty.Register("GeometryText", typeof (string), typeof (ComponentDrawing), new FrameworkPropertyMetadata
(
"",
FrameworkPropertyMetadataOptions
.
None));
private Canvas _canvas;
public ComponentDrawing()
{
InitializeComponent();
}
public string GeometryText
{
get { return ((string) GetValue(GeometryTextProperty)); }
set
{
SetValue(GeometryTextProperty, value);
ReadGeometryTextIntoDrawing(value);
}
}
private void ReadGeometryTextIntoDrawing(string fileText)
{
// Allow control to be visible at design time without errors shown.
// I.e. - don't execute code below at design time.
if (DesignerProperties.GetIsInDesignMode(this))
return;
// OK - we are a running application
//if (_canvas != null)
// return;
// OK - this is first time (-ish) we are running
if (ActualWidth == 0)
return;
// We have a valid screen to pain on
var componentDrawingService = ObjectFactory.GetInstance<IComponentDrawingService>();
//var commandTextProvider = ObjectFactory.GetInstance<ICommandTextProvider>();
//var fileText = ((IViewModelBase) DataContext).GeometryText;
// If getting the file text fails for some reason, just abort to avoid further problems.
if (fileText == null)
return;
var pg = componentDrawingService.GetDrawings(fileText, 0, ActualWidth, 0, ActualHeight);
_canvas = new Canvas();
foreach (var path in pg)
{
_canvas.Children.Add(path);
}
Content = _canvas;
}
private void UserControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
//ReadGeometryTextIntoDrawing();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
//ReadGeometryTextIntoDrawing();
}
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
//ReadGeometryTextIntoDrawing();
}
}
}
ComponentDrawing.xaml:
<UserControl x:Class="Rap1D.Rap1D_WPF.Controls.ComponentDrawing" 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" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"
DataContextChanged="UserControl_DataContextChanged" Loaded="UserControl_Loaded" SizeChanged="UserControl_SizeChanged">
<Grid Background="White">
<Path Stroke="Black"></Path>
</Grid>
</UserControl>
用法:
<Controls:RadPane x:Class="Rap1D.Rap1D_WPF.Controls.ProductComponentDetails" 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:Controls="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Docking" xmlns:Controls1="clr-namespace:Rap1D.Rap1D_WPF.Controls" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Header="{Binding DisplayName}">
<Controls1:ComponentDrawing GeometryText="{Binding GeometryText}" />
</Controls:RadPane>
视图模型对象(实现 INotifyPropertyChanged):
using System;
using Microsoft.Practices.Prism.Events;
using Rap1D.ExternalInterfaceWrappers.Interfaces;
using Rap1D.ModelLayer.Interfaces.Adapters;
using Rap1D.ModelLayer.Interfaces.Structure;
using Rap1D.ServiceLayer.Interfaces.Adapters;
using Rap1D.ServiceLayer.Interfaces.Providers;
using Rap1D.ViewModelLayer.Interfaces;
namespace Rap1D.ViewModelLayer.Implementations
{
public class ProductComponentViewModel : TreeViewItemViewModel, IProductComponentViewModel
{
...
public override string GeometryText
{
get
{
var pentaResponse = _commandTextProvider.GetCommandText(ProductComponent);
return DateTime.Now.ToString()+ pentaResponse.Payload;
}
}
...
} }
I have a custom control and a view model object. A property on the view model is bound to the custom control and I can see that the custom control actually receives the vaule from the view model object - yet my handler code (GeometryText.Set) is not executed. What am I doing wrong?!
Notice the event handlers on custom control where I've placed breakpoints- if I change the size of the window, I can inspect the GeometryText property in the watch window - and it's clearly updated in the cases where I expect it to.
Thanks for any input,
Anders, Denmark
ComponentDrawing.xaml.cs
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Rap1D.ServiceLayer.Interfaces.Services;
using StructureMap;
namespace Rap1D.Rap1D_WPF.Controls
{
/// <summary>
/// Interaction logic for ComponentDrawing.xaml
/// </summary>
public partial class ComponentDrawing
{
public static DependencyProperty GeometryTextProperty =DependencyProperty.Register("GeometryText", typeof (string), typeof (ComponentDrawing), new FrameworkPropertyMetadata
(
"",
FrameworkPropertyMetadataOptions
.
None));
private Canvas _canvas;
public ComponentDrawing()
{
InitializeComponent();
}
public string GeometryText
{
get { return ((string) GetValue(GeometryTextProperty)); }
set
{
SetValue(GeometryTextProperty, value);
ReadGeometryTextIntoDrawing(value);
}
}
private void ReadGeometryTextIntoDrawing(string fileText)
{
// Allow control to be visible at design time without errors shown.
// I.e. - don't execute code below at design time.
if (DesignerProperties.GetIsInDesignMode(this))
return;
// OK - we are a running application
//if (_canvas != null)
// return;
// OK - this is first time (-ish) we are running
if (ActualWidth == 0)
return;
// We have a valid screen to pain on
var componentDrawingService = ObjectFactory.GetInstance<IComponentDrawingService>();
//var commandTextProvider = ObjectFactory.GetInstance<ICommandTextProvider>();
//var fileText = ((IViewModelBase) DataContext).GeometryText;
// If getting the file text fails for some reason, just abort to avoid further problems.
if (fileText == null)
return;
var pg = componentDrawingService.GetDrawings(fileText, 0, ActualWidth, 0, ActualHeight);
_canvas = new Canvas();
foreach (var path in pg)
{
_canvas.Children.Add(path);
}
Content = _canvas;
}
private void UserControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
//ReadGeometryTextIntoDrawing();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
//ReadGeometryTextIntoDrawing();
}
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
//ReadGeometryTextIntoDrawing();
}
}
}
ComponentDrawing.xaml:
<UserControl x:Class="Rap1D.Rap1D_WPF.Controls.ComponentDrawing" 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" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"
DataContextChanged="UserControl_DataContextChanged" Loaded="UserControl_Loaded" SizeChanged="UserControl_SizeChanged">
<Grid Background="White">
<Path Stroke="Black"></Path>
</Grid>
</UserControl>
Usage:
<Controls:RadPane x:Class="Rap1D.Rap1D_WPF.Controls.ProductComponentDetails" 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:Controls="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Docking" xmlns:Controls1="clr-namespace:Rap1D.Rap1D_WPF.Controls" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Header="{Binding DisplayName}">
<Controls1:ComponentDrawing GeometryText="{Binding GeometryText}" />
</Controls:RadPane>
view model object (implementing INotifyPropertyChanged):
using System;
using Microsoft.Practices.Prism.Events;
using Rap1D.ExternalInterfaceWrappers.Interfaces;
using Rap1D.ModelLayer.Interfaces.Adapters;
using Rap1D.ModelLayer.Interfaces.Structure;
using Rap1D.ServiceLayer.Interfaces.Adapters;
using Rap1D.ServiceLayer.Interfaces.Providers;
using Rap1D.ViewModelLayer.Interfaces;
namespace Rap1D.ViewModelLayer.Implementations
{
public class ProductComponentViewModel : TreeViewItemViewModel, IProductComponentViewModel
{
...
public override string GeometryText
{
get
{
var pentaResponse = _commandTextProvider.GetCommandText(ProductComponent);
return DateTime.Now.ToString()+ pentaResponse.Payload;
}
}
...
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果通过绑定更改,则不会调用依赖属性设置器。如果您想以某种方式对依赖属性值的更改做出反应,您应该在属性元数据中注册回调:
http://msdn.microsoft.com/en-us/library/ms557294.aspx
类似的东西(不确定它是否可以编译,如果有问题请告诉我):
Dependency property setters are not invoked if changed by binding. If you want to somehow react on dependency property value changing you should register a callback in property metadata:
http://msdn.microsoft.com/en-us/library/ms557294.aspx
something like that (not sure it is compilable, let me know if something wrong):