将 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
;你从来没有告诉过它。
Kangaroo
的 Age
属性 在改变时引发 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}" />
如何将设计器中 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
;你从来没有告诉过它。
Kangaroo
的 Age
属性 在改变时引发 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}" />