wpf 数据绑定自定义控件 - 为什么自定义控件未检测到对我的数据源的更改?

发布于 2024-10-16 08:25:49 字数 6235 浏览 1 评论 0原文

我有一个自定义控件和一个视图模型对象。视图模型上的属性绑定到自定义控件,我可以看到自定义控件实际上从视图模型对象接收值 - 但我的处理程序代码 (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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

没有心的人 2024-10-23 08:25:49

如果通过绑定更改,则不会调用依赖属性设置器。如果您想以某种方式对依赖属性值的更改做出反应,您应该在属性元数据中注册回调:

http://msdn.microsoft.com/en-us/library/ms557294.aspx

类似的东西(不确定它是否可以编译,如果有问题请告诉我):

public static DependencyProperty GeometryTextProperty =
     DependencyProperty.Register(... , new FrameworkPropertyMetadata(GeometryTextCallback));

public static void GeometryTextCallback(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
    // cast source to your type and invoke method from your setter
    ((ComponentDrawing)source)ReadGeometryTextIntoDrawing(value);
}

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):

public static DependencyProperty GeometryTextProperty =
     DependencyProperty.Register(... , new FrameworkPropertyMetadata(GeometryTextCallback));

public static void GeometryTextCallback(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
    // cast source to your type and invoke method from your setter
    ((ComponentDrawing)source)ReadGeometryTextIntoDrawing(value);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文