【问题标题】:WPF UserControl Dependency Property not workingWPF用户控件依赖属性不起作用
【发布时间】:2018-02-02 08:19:10
【问题描述】:

在一个 WPF 项目(下面的代码)中,我有一个 UserControl 类型为 MyUserControl 的依赖属性,称为 MyOrientation 类型为 Orientation

MainWindow 上,我有两个MyUserControl 实例,通过XAML 我将一个Orientation 属性设置为Horizontal,另一个实例设置为Vertical

我已将 MyOrientation 属性设为 DP,因为我希望能够像本示例中那样直接在 XAML 中设置它或使用绑定。

我的问题是,当我运行项目时,UserControl 的两个实例都显示为 Orientation = Horizo​​ntal?

谁能告诉我我做错了什么以及如何解决它?

非常感谢。

代码如下:

MYUSERCONTROLVIEWMODEL:

public class MyUserControlViewModel : ViewModelBase
{
    private Orientation _myOrientation;
    public Orientation MyOrientation
    {
        get { return _myOrientation; }
        set
        {
            if (_myOrientation == value)
                return;
            _myOrientation = value;
            OnPropertyChanged();
        }
    }

}

MYUSERCONTROL.XAML

<UserControl x:Class="TestUserControlDPProblem.MyUserControl"
         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:TestUserControlDPProblem"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="root">

    <Grid.DataContext>
        <local:MyUserControlViewModel/>
    </Grid.DataContext>

    <StackPanel Orientation="{Binding MyOrientation}">
        <TextBlock>Hello</TextBlock>
        <TextBlock>There</TextBlock>
    </StackPanel>
</Grid>

MYUSERCONTROL 代码隐藏:

public partial class MyUserControl : UserControl
{
    MyUserControlViewModel _vm;

    public MyUserControl()
    {
        InitializeComponent();

        _vm = root.DataContext as MyUserControlViewModel;
    }

    public static readonly DependencyProperty MyOrientationProperty = DependencyProperty.Register("MyOrientation", typeof(Orientation), typeof(MyUserControl), new FrameworkPropertyMetadata(Orientation.Vertical, new PropertyChangedCallback(OnMyOrientationChanged)));

    private static void OnMyOrientationChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        var myUserControl = o as MyUserControl;
        myUserControl?.OnMyOrientationChanged((Orientation)e.OldValue, (Orientation)e.NewValue);
    }

    protected virtual void OnMyOrientationChanged(Orientation oldValue, Orientation newValue)
    {
        _vm.MyOrientation = newValue;
    }
    public Orientation MyOrientation
    {
        get
        {
            return (Orientation)GetValue(MyOrientationProperty);
        }
        set
        {
            SetValue(MyOrientationProperty, value);
        }
    }

}

主窗口.XAML

<Window x:Class="TestUserControlDPProblem.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:TestUserControlDPProblem"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <StackPanel>
        <local:MyUserControl Margin="10" MyOrientation="Horizontal"/>
        <local:MyUserControl Margin="10" MyOrientation="Vertical"/>
    </StackPanel>


</Grid>

【问题讨论】:

    标签: c# wpf xaml user-controls wpf-controls


    【解决方案1】:

    UserControl 的“内部”视图模型没有意义,不应该存在。您应该通过 RelativeSource 或 ElementName 绑定直接绑定到依赖属性:

    <StackPanel Orientation="{Binding MyOrientation,
                              RelativeSource={RelativeSource AncestorType=UserControl}}">
    

    您甚至不需要 PropertyChangedCallback:

    public partial class MyUserControl : UserControl
    {
        public MyUserControl()
        {
            InitializeComponent();
        }
    
        public static readonly DependencyProperty MyOrientationProperty =
            DependencyProperty.Register(
                nameof(MyOrientation), typeof(Orientation), typeof(MyUserControl), 
                new FrameworkPropertyMetadata(Orientation.Vertical));
    
        public Orientation MyOrientation
        {
            get { return (Orientation)GetValue(MyOrientationProperty); }
            set { SetValue(MyOrientationProperty, value); }
        }
    }
    

    【讨论】:

    • 感谢您的回复。您的更改确实可以完成工作。我想说“内部”视图模型的实现是为了让 UserControl 能够拥有自己的 DataContext。或者,无论如何,这就是意图。但是我仍然很困惑为什么我的代码不起作用。
    • 你不应该那样做。 DataContext 应该只继承自 UserControl 的父元素,并且 UserControl 应该只公开绑定到继承 DataContext 中的视图模型对象的属性的依赖项属性。这些 Binding 不应在 UserControl 的 XAML 中“内部”声明,而应在某处使用该控件时声明。
    • 我试图遵循 Brian Noyes 的博客中给出的建议:briannoyesblog.azurewebsites.net/2015/09/19/…
    • 我没读过,但如果它建议 UserControl 应该有自己的视图模型,那就大错特错了。不要相信互联网上的一切。有大量由“专家”撰写的博客展示了带有私有视图模型的 UserControl。阅读这些博客的人往往会在这里问为什么他们绑定到他们的 UserControls 的依赖属性不起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多