在代码中从WPF DataContext获取值的简单、通用的方法
本文关键字:简单 方法 获取 代码 WPF DataContext | 更新日期: 2023-09-27 18:05:13
假设我有一个绑定到某个DataContext的WPF控件。现在假设我有一些UI代码需要从DataContext获取一些值。我怎么做呢?
我知道以下的解决方法:
-
将DataContext强制转换为其原始类型,例如
var myValue = ((MyViewModel)myControl.DataContext).SomeProperty;
或
var myValue = ((DataRowView)myControl.DataContext).Item("SomeDatabaseField");
我不喜欢这样,因为这意味着在我的UI代码中我需要关于底层数据源类型的信息
-
将所需值绑定到某个UI字段并从中提取,例如
<Button Click="..." Tag="{Binding SomeProperty}" />
和代码
var myValue = (TypeOfMyValue)myButton.Tag;
是否有一些通用的方法从DataContext中提取一个值,即做任何Binding
做得到的值?我在找这样的东西:
var myValue = SomeGenericExtractMethod(myControl.DataContext, "SomeProperty");
我很确定这样的东西存在(毕竟,Binding
是这样工作的),我只是找不到它…
我找到了一种既适用于ViewModel类(CLR属性)又适用于绑定到ADO的列表的方法。. NET DataTables (DataRowView字段),它将使用两者提供的类型描述符:
var myValue = TypeDescriptor.GetProperties(myControl.DataContext)["SomeProperty"]
.GetValue(myControl.DataContext);
下面是一个简短的工作示例:
var vm = new { MyString = "Test1" }; // ViewModel
var dt = new DataTable();
dt.Columns.Add("MyString", typeof(String));
dt.Rows.Add("Test2");
var drv = dt.DefaultView[0]; // DataRowView
var value1 = TypeDescriptor.GetProperties(vm)["MyString"].GetValue(vm);
var value2 = TypeDescriptor.GetProperties(drv)["MyString"].GetValue(drv);
// value1 = "Test1", value2 = "Test2"
答案是反射。这将适用于非索引属性:
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
this.DataContext = new MyViewModel();
var myValue = this.DataContext.GetType().GetProperty("MyIntValue").GetValue(this.DataContext, null);
}
}
public class MyViewModel
{
private int myIntValue = 6;
public int MyIntValue
{
get
{
return this.myIntValue;
}
}
}
//Into the View:
public Ingreso Ingreso { get; set; }
public CapturaDatos()
{
InitializeComponent();
Ingreso = new Ingreso();
DataContext = Ingreso;
}
//进入模型
internal class IngresoViewModel
{
public Ingreso IngresoDetails { get; set; }
}
//Into de View XAML
xmlns:modelo="clr-namespace:WpfApp2.ViewModel"
<Page.DataContext>
<modelo:IngresoViewModel/>
</Page.DataContext>
<TextBox x:Name="textBoxCurp" TextChanged="textBoxCurp_TextChanged" CharacterCasing="Upper" Text="{Binding IngresoDetails.Curp}" />
然后您可以在XAML文件或代码中使用Ingreso DataBinding
您可能必须自己构建它。我们在工作中这样做了,但我不能分享代码,因为它是内部资产。虽然不太容易,但也不太难,考虑到也尊重索引属性。尽管如此,这应该在一天内完成。您可以使用反射来获取值,但请确保缓存生成的getter。没有比这更多的了。真的……:)
也许在这方面有更多的信息,因为有些人认为这不是一个好方法:给定一个复杂的属性路径,循环遍历路径并一个接一个地解析对象。创建一个获取DataContext-Instance的解析器类。创建getter-delegate,并为propertytype和propertypath(只是段)缓存它们。这真的很快。WPF唯一不同的地方是Value-Getter。它分析属性的类型。INotifyPropertyChanged-Supporters和dependyobjects的处理方式是不同的,但是如果缓存委托,不会造成太大的性能问题。