更改视图模型

时间:2016-07-07 21:22:37

标签: c# xaml mvvm uwp xbind

我已经简化了应用以显示我的问题

当我点击按钮时,它会更改Text的{​​{1}}属性并更新ViewModel

MainPage.xaml中

TextBlock.Text

MainPage.xaml.cs中

<StackPanel>
  <Button  Click="ButtonBase_OnClick">Button to change text</Button>
  <TextBlock Text="{x:Bind ViewModel.Text, Mode=OneWay}"></TextBlock>
</StackPanel>

ViewModel 类有一个字符串属性(Text)并实现了 INotifyPropertyChange 接口。

问题在ctor中未设置 public MainPage() { ViewModel = new ViewModel(); this.InitializeComponent(); } private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { ViewModel.Text = "x:Bind works"; } 时启动(即viewModel为null并在运行时更改):

ViewModel

Complited 绑定不起作用(文本未更改)我无法弄清楚为什么会这样...我需要从null更改viewModel(vm为null因为它正在等待真实应用中的一些数据)

2 个答案:

答案 0 :(得分:2)

{x:Bind} 绑定(通常称为编译绑定)使用生成的代码来实现其好处。在XAML加载时, {x:Bind} 将转换为您可以将其视为绑定对象的内容,并且此对象从数据源上的属性获取值。这些生成的代码可以在 obj 文件夹中找到,其名称类似于(对于C#) <view name>.g.cs

对于您的代码,生成的代码如下:

// Update methods for each path node used in binding steps.
private void Update_(global::UWP.BlankPage3 obj, int phase)
{
    if (obj != null)
    {
        if ((phase & (NOT_PHASED | DATA_CHANGED | (1 << 0))) != 0)
        {
            this.Update_ViewModel(obj.ViewModel, phase);
        }
    }
}
private void Update_ViewModel(global::UWP.ViewModel obj, int phase)
{
    this.bindingsTracking.UpdateChildListeners_ViewModel(obj);
    if (obj != null)
    {
        if ((phase & (NOT_PHASED | DATA_CHANGED | (1 << 0))) != 0)
        {
            this.Update_ViewModel_Text(obj.Text, phase);
        }
    }
}

...

private global::UWP.ViewModel cache_ViewModel = null;
public void UpdateChildListeners_ViewModel(global::UWP.ViewModel obj)
{
    if (obj != cache_ViewModel)
    {
        if (cache_ViewModel != null)
        {
            ((global::System.ComponentModel.INotifyPropertyChanged)cache_ViewModel).PropertyChanged -= PropertyChanged_ViewModel;
            cache_ViewModel = null;
        }
        if (obj != null)
        {
            cache_ViewModel = obj;
            ((global::System.ComponentModel.INotifyPropertyChanged)obj).PropertyChanged += PropertyChanged_ViewModel;
        }
    }
}

在这里,我只是复制一些与您的问题相关的方法。通过这些方法,您可以在更新TextBlockPropertyChanged听众之前发现,它会检查ViewModel是否为null。如果是null,则不会执行任何操作。因此,要使 {x:Bind} 工作,我们必须在加载页面之前初始化ViewModel。这就是为什么 {x:Bind} ViewModel事件中初始化Button.Click时无效的原因。

要解决此问题,您可以为INotifyPropertyChanged实施ViewModel接口,例如Filip说,以便在ViewModel更改时(从null更改为{},可以通知生成的代码{1}})并更新UI。

但我认为你可以在构造函数中初始化new ViewModel()。初始化ViewModel时,您可以首先设置等待ViewModel的属性:

null

然后在您的日期准备就绪时更新这些属性。这样,您就无法在页面上实现public MainPage() { ViewModel = new ViewModel() { Text = null }; this.InitializeComponent(); } 界面。

除了这些,还有另一种更便宜的方法,你可以调用INotifyPropertyChanged方法来强制在初始化this.Bindings.Update();之后更新绑定:

ViewModel

答案 1 :(得分:0)

您是否在页面上实现了INotifyPropertyChanged

public sealed partial class MainPage : Page, INotifyPropertyChanged
{
    private ViewModel viewModel;

    public ViewModel ViewModel
    {
        get { return viewModel; }
        set 
        {
            viewModel = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ViewModel)));
        }
    }

    public MainPage()
    {
        ViewModel = new ViewModel { };
        this.InitializeComponent();
    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        ViewModel = new ViewModel {  };//this line has been added
        ViewModel.Text = "x:Bind does not work";
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

这适合我。