将 DataContext 转换为本地值

Converting DataContext to a Local Value

如何将设计器中 DataContext 的属性更改传播到实际的数据上下文对象?这可能吗?

这是我的尝试 - 我将 DataContext 转换为 XML 中的本地值 - 我认为我在设计器中对其所做的任何更改都会反映在 DataContext 对象上。

这里是 SSCCE。我有一个名为 MammalUC 的 UserControl 和一个名为 Kangaroo 的 class。我使用 class Kangaroo 的对象作为 DataContext。下面的代码显示了这一点。

using System.ComponentModel;
using System.Windows.Controls;

namespace WPFTestABC
{
    /// <summary>
    /// User Control :  Interaction logic for MammalUC.xaml
    /// </summary>
    public partial class MammalUC : UserControl
    {
        public MammalUC()
        {
            InitializeComponent();
            Kang = new Kangaroo();
            this.DataContext = Kang;
        }

        private Kangaroo kang;

        /// <summary>
        /// This is the datacontext.
        /// </summary>
        [Category("ForDebug")]
        [TypeConverter(typeof(ExpandableObjectConverter))]
        public Kangaroo Kang
        {
            get{ return kang;}
            set {kang = value;}
        }
    }

    /// <summary>
    /// Kangaroo class.
    /// </summary>
    public class Kangaroo : INotifyPropertyChanged
    {
        private int age;
        public int Age
        {
            get { return age; }
            set
            {
                age = value;
                OnPropertyChanged("Age");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}

我像这样将年龄 属性 绑定到 UserControl -

<UserControl x:Class="WPFTestABC.MammalUC"
             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:WPFTestABC"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TextBox Text="{Binding Age}" Background="#FFD88787"></TextBox>
    </Grid>
</UserControl>

然后我将 MammalUC 放在 window 上。然后将 Kang 对象转换为本地值(我也尝试过将其作为静态资源)。在设计器 属性 网格中,我更改了值,但我没有看到正在更新的值。

<Window x:Class="WPFTestABC.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:WPFTestABC"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <!--<Window.Resources>
        <local:Kangaroo x:Key="Kangaroo1" Age="65"/>
    </Window.Resources>-->
    <Grid>
        <!--Using Static Resource -->
        <local:MammalUC HorizontalAlignment="Left" Height="100" Margin="210,115,0,0" VerticalAlignment="Top" Width="100">
            <!--Converting to local resource-->
            <local:MammalUC.Kang>
                <local:Kangaroo Age="85"/> <!--Value never updates-->
            </local:MammalUC.Kang>
        </local:MammalUC>
    </Grid>
</Window>

Then convert the Kang object to a local value

我不太能猜到你想在那里说什么。我没有看到任何对象被转换为任何东西,我不知道你所说的 "local value" 是什么意思。我不知道你认为你在做什么。

但这就是你正在做的事情:

<!--Using Static Resource -->
<local:MammalUC HorizontalAlignment="Left" Height="100" Margin="210,115,0,0" VerticalAlignment="Top" Width="100">
    <!--Converting to local resource-->
    <local:MammalUC.Kang>
        <local:Kangaroo Age="85"/> <!--Value never updates-->
    </local:MammalUC.Kang>
</local:MammalUC>

这个XAML里面没有"static resource",也没有"local resource"。 You should find out what the word "resource" means in WPF

您正在做的是 Kangaroo [=71] 的新实例替换 Kang 属性 的现有值=].

为什么那行不通?原因如下:

    private Kangaroo kang;

    /// <summary>
    /// This only becomes the datacontext if you explicitly assign it 
    /// to this.DataContext.
    /// </summary>
    [Category("ForDebug")]
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public Kangaroo Kang
    {
        get{ return kang;}
        set {kang = value;}
    }

你从来没有告诉任何人你改变了它。您没有更新数据上下文。返回构造函数,将 DataContext 设置为 Kang 在那个时刻 的值 。当您给 Kang 一个新值时会发生什么?没什么。它设置私有 kang,仅此而已。当然它不会更新 DataContext;你从来没有告诉过它。

KangarooAge 属性 在改变时引发 PropertyChanged ,这样就可以了。 Kang 没有什么可比的。现在,控件不使用 INotifyPropertyChanged;他们使用依赖属性。依赖属性在更改时也会引发通知事件,但您也可以在 XAML 中对它们进行绑定,因此它们更适合控件。

您可以添加类型为 Kangaroo 的新依赖项 属性 并让它更新 DataContext,但有一种更简单的方法可以做到这一点。

解决此问题的方法如下:删除 private Kangaroo kang; 并按如下方式更改 属性。

    public Kangaroo Kang
    {
        get { return (Kangaroo)DataContext; }
        set { DataContext = value;}
    }

    public MammalUC()
    {
        InitializeComponent();

        //  This sets the DataContext. 
        Kang = new Kangaroo();
    }

DataContext 是一个依赖项 属性。设置它,通知将在幕后飞来飞去。事情会发生的。

您不能使 Kang 成为绑定的目标。为此,您必须将其设为依赖项 属性:

#region Kang Property
public Kangaroo Kang
{
    get { return (Kangaroo)GetValue(KangProperty); }
    set { SetValue(KangProperty, value); }
}

public static readonly DependencyProperty KangProperty =
    DependencyProperty.Register(nameof(Kang), typeof(Kangaroo), typeof(MammalUC),
        new PropertyMetadata(null));
#endregion Kang Property

XAML:

<UserControl 
    x:Class="WPFTestABC.MammalUC"
    ...blah blah blah...
    DataContext="{Binding Kang, RelativeSource={RelativeSource Self}}"
    >

然后你可以给你的主视图模型一个 public Kangaroo SelectedKangaroo { /* INPC garble */ } 属性,然后将它绑定到你的主视图模型 window:

<local:MammalUC Kang="{Binding SelectedKangaroo}" />