【问题标题】:How do I properly bind my model in WPF?如何在 WPF 中正确绑定我的模型?
【发布时间】:2015-06-27 18:01:15
【问题描述】:

我有一个名为 ViewModel 的类,它实现了 INotifyPropertyChanged 接口。在我的 XAML 中,我有 3 个文本框,它们的绑定属性与我的 ViewModel 属性匹配:

TestsOrdered 已完成测试 剩余测试数

我的代码隐藏中有一个 PropertyChanged 事件处理程序。我有一个附加到 XAML 窗口的上下文“MyContext”。我不确定为什么当我更改 TestsOrdered 和 TestsCompleted 值时 UI 没有更新。我希望 UI 在我从文本框中跳出时更新,但直到我从 TestsRemaining 文本框中跳出时才更新。我的设计缺陷在哪里?

public partial class MainWindow : Window
{
    public ViewModel vm;

    public MainWindow()
    {
        InitializeComponent();
        vm = new ViewModel();
        //ct = new CompletionTime();
        //ct.TestsOrdered = 8000;

        vm.Name = "John Doe";
        vm.TestsCompleted = 0;
        vm.TestsOrdered = 0;
        vm.TestsRemaining = 0;

        this.MyContext.DataContext = vm;
    }

    private void btnName_Click(object sender, RoutedEventArgs e)
    {
        vm.Name = "Joe";
    }
}

public class ViewModel : INotifyPropertyChanged
{
    private string name;
    private int mTestsOrdered;
    private int mTestsRemaining;
    private int mTestsCompleted;

    public string Name
    {
        get { name; }
        set
        {
            if (name != value)
            {
                name = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("Name"));
                }
            }
        }
    }


    public int TestsOrdered
    {
        get { return mTestsOrdered; }
        set
        {
            if (mTestsOrdered != value)
            {
                mTestsOrdered = value;
                PropertyChanged(this, new PropertyChangedEventArgs("TestsOrdered"));
            }
        }
    }


    public int TestsCompleted
    {
        get { return mTestsCompleted; }
        set
        {
            if (mTestsCompleted != value)
            {
                mTestsCompleted = value;
                PropertyChanged(this, new PropertyChangedEventArgs("TestsCompleted"));
            }
        }
    }


    public int TestsRemaining
    {
        get { return TestsOrdered - TestsCompleted; }
        set
        {
            if (mTestsRemaining != value)
            {
                mTestsRemaining = value;
                PropertyChanged(this, new PropertyChangedEventArgs("TestsRemaining"));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

MyContext 是保存 ViewModel 对象的 DataContext。

XAML:

 <Grid Margin="-1,-9,1,9">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="244*"/>
            <ColumnDefinition Width="251*"/>
        </Grid.ColumnDefinitions>
        <TextBox Width="100"  HorizontalAlignment="Center" Margin="96.791,40,54,0" TextWrapping="Wrap" Text="{Binding Path=Name}" VerticalAlignment="Top" Grid.Column="1"/>

        <Button x:Name="btnName" Content="Button" HorizontalAlignment="Left" Margin="171,210,0,0" VerticalAlignment="Top" Width="148" Height="47" Click="btnName_Click" Grid.ColumnSpan="2"/>
        <TextBox Grid.Column="0" HorizontalAlignment="Left" Height="23" Margin="97,84,0,0" TextWrapping="Wrap" Text="{Binding Path=TestsOrdered}" VerticalAlignment="Top" Width="120"/>
        <TextBox Grid.Column="0" HorizontalAlignment="Left" Height="23" Margin="97,112,0,0" TextWrapping="Wrap" Text="{Binding Path=TestsCompleted}" VerticalAlignment="Top" Width="120"/>
        <TextBox Grid.Column="0" HorizontalAlignment="Left" Height="23" Margin="97,140,0,0" TextWrapping="Wrap" Text="{Binding Path=TestsRemaining}" VerticalAlignment="Top" Width="120"/>

    </Grid>

【问题讨论】:

  • 能否提供一个在xaml中绑定属性的代码示例?
  • 另外,MyContext 是什么?
  • 嗨,鹦鹉螺。我添加了一些 XAML。我的印象是我在 XAML 中分配绑定路径,而 WPF 在幕后负责其余的工作。我错过了什么?
  • 您是对的,但是您将视图模型实例放置在窗口实例的错误属性上。 Binding 类使用 Window 属性:DataContext 作为要绑定的默认对象。你可以说你的绑定的完整路径是&lt;WindowInstance&gt;.DataContext.&lt;PathDefinded&gt;。解决方案是在属性DataContext 上设置您的视图模型实例。我会写一个答案给你。

标签: c# wpf xaml mvvm


【解决方案1】:

您的绑定和属性已正确编写。但是,问题在于您将视图模型实例分配给Window。您需要在属性 DataContext 上设置视图模型的实例,才能使绑定起作用。像这样:

 public MainWindow()
{
    InitializeComponent();
    vm = new ViewModel();
    //ct = new CompletionTime();
    //ct.TestsOrdered = 8000;

    vm.Name = "John Doe";
    vm.TestsCompleted = 0;
    vm.TestsOrdered = 0;
    vm.TestsRemaining = 0;

    //this.MyContext.DataContext = vm;
    this.DataContext = vm; // <-- Like so
}

原因在于绑定的工作方式。如果没有提供其他源(SourceRelativeSourceBindingElementName 属性),绑定将使用分配给它们的FrameworkElementDataContext 属性。在您的情况下,TextBox

当您设置 Window 的 DataContext 属性时,它的所有子对象都会继承该对象实例,以及它们的子对象,依此类推。

尝试更改您的 ViewModel 分配,您将看到绑定工作。

//干杯

【讨论】:

  • 嗨,Nautious。正如你提到的,我改变了它。奇怪的是,它仍然不会计算/绑定,直到我从最后一个文本框中跳出。我仍然缺少一些东西。
  • 好的。我知道出了什么问题。我期待模型中的所有属性都能更新。我想我应该将 EventArgs 的 name 属性留空。
  • 好的,绑定现在与属性建立了连接。新问题是它的更新方式。更改绑定以包含以下内容:UpdateSourceTrigger = PropertyChanged。文本框的默认值为LostFocus
  • EventArgs 中的空属性名称将触发所有绑定的更新。
  • 从技术上讲,将上下文设置为另一个元素是完全有效的,只要他在所述元素上使用x:Name="MyContext",从上面的 XAML 代码中无法确定他是否这样做,因为它只显示了整个 XAML 代码的一部分
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-05
  • 2011-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多