将DataContext转换为本地值

时间:2017-06-23 16:04:55

标签: wpf datacontext

如何将设计器中DataContext的属性更改为实际的datacontext对象?这可能吗?

以下是我尝试的内容 - 我将DataContext转换为XML中的本地值 - 认为我在设计器中对其进行的任何更改都会反映在DataContext对象上。

这是SSCCE。我有一个名为MammalUC的UserControl和一个名为Kangaroo的类。我使用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));
            }
        }
    }
}

我将Age属性绑定到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放在窗户上。然后将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>

1 个答案:

答案 0 :(得分:2)

  

然后将Kang对象转换为本地值

我对你在那里试图说什么没有很好的猜测。我没有看到任何对象被转换成任何东西,我不知道你的意思是“本地价值”。我不知道你在想什么。

但这是你正在做的事情:

<!--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中没有“静态资源”,也没有“本地资源”。 You should find out what the word "resource" means in WPF

您正在做的是使用Kang类的新实例替换 Kangaroo属性的现有值。

为什么不起作用?原因如下:

    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;你从来没有告诉过它。

Age Kangaroo属性在PropertyChanged更改时会引发Kang,因此可行。与INotifyPropertyChanged没有任何可比性。现在,控件不使用Kangaroo;他们使用依赖属性。依赖属性还会在更改时引发通知事件,但您也可以在XAML中对它们进行绑定,因此它们更适合于控件。

您可以添加类型为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 成为绑定的目标。为此,你必须去做一个依赖属性:

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

XAML:

public Kangaroo SelectedKangaroo { /* INPC garble */ }

然后你可以给你的主视图模型一个<local:MammalUC Kang="{Binding SelectedKangaroo}" /> 属性,并将它绑定在你的主窗口中:

{{1}}