在代码中从WPF DataContext获取值的简单通用方法

blpfk2vs  于 2023-05-13  发布在  其他
关注(0)|答案(4)|浏览(342)

假设我有一个绑定到某个DataContext的WPF控件。现在假设我有一些UI代码需要从DataContext获取一些值。我该怎么做?
我知道以下解决方法:
1.将DataContext转换为它的原始类型,例如

var myValue = ((MyViewModel)myControl.DataContext).SomeProperty;

var myValue = ((DataRowView)myControl.DataContext).Item("SomeDatabaseField");

我不喜欢这样,因为这意味着 * 在我的UI代码中 * 我需要关于底层数据源类型的信息。
1.将所需的值绑定到某个UI字段并从中提取,例如

<Button Click="..." Tag="{Binding SomeProperty}" />

在代码中

var myValue = (TypeOfMyValue)myButton.Tag;

是否有某种通用的方法可以从DataContext中提取值,即执行Binding所做的任何操作来获取值?我在找这样的东西:

var myValue = SomeGenericExtractMethod(myControl.DataContext, "SomeProperty");

我很确定这样的东西是存在的(毕竟,Binding就是这样工作的),我只是找不到它...

aoyhnmkz

aoyhnmkz1#

我发现了一种既适用于ViewModel类(CLR属性)又适用于绑定到ADO.NET DataTables(DataRowView字段)的列表的方法,即使用两者提供的TypeDescriptor

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"
vi4fp9gy

vi4fp9gy2#

答案是反思。这将适用于非索引属性:

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;
        }
    }
}
idv4meu8

idv4meu83#

//进入视图:

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。

j8yoct9x

j8yoct9x4#

您可能需要自己构建它。我们在工作中这样做了,但我不能分享代码,因为它是内部资产。虽然这不是很容易,但也不太难考虑也尊重索引属性。但这件事还是要在一天之内完成。您使用反射来获取值,但要确保缓存生成的getter。没有比这更多。真的...:)
也许更多的信息,因为有些人认为这不是一个好方法:给定一个复杂的属性路径,您可以循环遍历路径并逐个解析对象。创建一个获取DataContext-Instance的Resolver-Class。创建getter-delegates并缓存propertytype和propertypath的getter-delegates(只缓存段)。这真的很快。WPF做的唯一不同的事情是价值获取者。它分析其类型的属性。INotifyPropertyChanged-Supporters和DependendendyObject的处理方式不同,但如果缓存委托,这不会造成太大的性能问题。

相关问题