【问题标题】:textblock not updating when property changed in model模型中的属性更改时文本块不更新
【发布时间】:2016-10-26 18:24:46
【问题描述】:

我的文本块没有更新更新我的模型中的值。如果我更新 ViewModel 中的文本块,它可以工作,所以我的绑定似乎是正确的。我认为问题在于我在模型中更新它的方式,但我不确定为什么我的 observableCollection 也只更新,因为我来回传递值不确定这是好的 MVVM 策略。

XAML 部分:

<Grid>
    <TextBox x:Name="NewLabelBx" HorizontalAlignment="Left" Height="23" Margin="54,449,0,0" TextWrapping="Wrap" Text="{Binding NewLabel,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="314"/>
    <Button x:Name="NewLabelBtn" Content="Add Label" HorizontalAlignment="Left" Margin="293,490,0,0" VerticalAlignment="Top" Width="75" RenderTransformOrigin="0.518,-0.709" Command="{Binding Path=NewLabelBtn}" />
    <TextBlock x:Name="FilesProcessedBlck" HorizontalAlignment="Left" Margin="54,507,0,0" TextWrapping="Wrap" Text="{Binding FilesProcessedBlck,  UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" RenderTransformOrigin="-0.7,0.562" Width="65"/>
</Grid>

ViewModel 部分:

    public class P4LabelBatteryViewModel : BindableBase
{
    private P4LabelBatteryModel p4LabelBatteryModel = new P4LabelBatteryModel();

    public P4LabelBatteryViewModel()
    {
        P4LabelBatteryModel p4LabelBatteryModel = new P4LabelBatteryModel();

        this.GetBatteryBtn = new DelegateCommand(chooseFile, canChooseFile);
        this.NewLabelBtn = new DelegateCommand(chooseNewLabel, canNewLabel).ObservesProperty(() => NewLabel);
        this.FilesProcessedBlck = 2;  //this works.
    }

    //other code here

    private void chooseNewLabel()
    {
        if (ScriptCollection.Count > 0)
        {
            ScriptCollection = P4LabelBatteryModel.TagsFilesModel(NewLabel, ScriptCollection);
        }
    }


    private int _filesProcessedBlck;
    public int FilesProcessedBlck
    {
        get
        {
            return _filesProcessedBlck;
        }
        set
        {
            SetProperty(ref _filesProcessedBlck, value);
        }

    }

    private ObservableCollection<ScriptModel> _scriptCollection = new ObservableCollection<ScriptModel>();
    public ObservableCollection<ScriptModel> ScriptCollection
    {
        get
        {
            return _scriptCollection;
        }
        set
        {
            SetProperty(ref _scriptCollection, value);
        }

    }        

}

模型部分:

   class P4LabelBatteryModel
{

   public static ObservableCollection<ScriptModel> TagsFilesModel(string NewLabel, ObservableCollection<ScriptModel> observableCollection)
    {
        string newLabel = NewLabel;
        var scriptsToTagColl = observableCollection;
        string[] files = null;

        var _p4LabelBatteryViewModel = new P4LabelBatteryViewModel();
        _p4LabelBatteryViewModel.FilesProcessedBlck++;  //xaml is never updated with this value.

        //This will generate an IPC when returned
        ObservableCollection<ScriptModel> newCollection = new ObservableCollection<ScriptModel>();

        //code here that modifies newCollection  xaml updates when this returns, _p4LabelBatteryViewModel.FilesProcessedBlck++; does not.

        return newCollection;
    }
}

当我运行调试器时,我可以看到 P4LabelBatteryViewModel.FilesProcessedBlck 正在修改,但 XAML 没有更新。

【问题讨论】:

  • 您的.DataContext 似乎有问题。看起来您没有正确分配它,因此您的 TextBlock 指向 P4LabelBatteryViewModel 的一个实例,而您正在 ObservableCollection 代码中创建第二个实例。

标签: c# wpf mvvm prism-6


【解决方案1】:
    var _p4LabelBatteryViewModel = new P4LabelBatteryViewModel();
    _p4LabelBatteryViewModel.FilesProcessedBlck++;  //xaml is never updated with this value.

好的,如果 TextBlock 一开始就显示了您期望的内容,那么您的 XAML 必须具有视图模型的副本。但是在这个方法中,你创建了同一个视图模型类的一个新实例,在它上面设置了一个属性,然后你就什么也不做了。它超出了范围,垃圾收集器最终吃掉了它。它从来都不是任何视图的 DataContext,任何地方,所以它当然对 UI 没有影响。

_p4LabelBatteryViewModel 是一个局部变量。该方法之外的任何人都没有看到它,甚至不知道它的存在。如果您想更改实际显示在 UI 中的视图模型的副本,您必须更改它的 该实例。另外,请不要在局部变量前面加上_。按照惯例,前导下划线表示属于某个类的私有字段。最好遵守该约定,以避免混淆。

视图模型应该更新它自己的FilesProcessedBlck 属性。在任何情况下,让模型负责维护视图模型的状态都不是一个好主意。那是viewmodel的问题,让他处理。

private void chooseNewLabel()
{
    if (ScriptCollection.Count > 0)
    {
        ScriptCollection = P4LabelBatteryModel.TagsFilesModel(NewLabel, ScriptCollection);
        ++FilesProcessedBlck;
    }
}

在模型中...

public static ObservableCollection<ScriptModel> TagsFilesModel(string NewLabel, IList<ScriptModel> scriptsToTagColl)
{
    string newLabel = NewLabel;
    string[] files = null;

    //  This will generate an IPC when returned
    ObservableCollection<ScriptModel> newCollection = new ObservableCollection<ScriptModel>();

    //code here that modifies newCollection  xaml updates when this returns, _p4LabelBatteryViewModel.FilesProcessedBlck++; does not.

    return newCollection;
}

我做了一些其他的小改动来简化TagsFilesModel。例如,它没有理由要求调用者传入ObservableCollection&lt;T&gt;。你可能永远没有理由给它任何其他东西,但如果你在代码中养成这种灵活性的习惯,它就会得到回报。

还有一个项目。这是无害的,但值得了解:

<TextBlock 
    x:Name="FilesProcessedBlck" 
    HorizontalAlignment="Left" 
    Margin="54,507,0,0" 
    TextWrapping="Wrap" 
    Text="{Binding FilesProcessedBlck}" 
    VerticalAlignment="Top" 
    RenderTransformOrigin="-0.7,0.562" 
    Width="65"
    />

UpdateSourceTrigger=PropertyChangedBinding 中没有任何用途。绑定的“来源”是 viewmodel 属性; “目标”是 UI 控件属性。 UpdateSourceTrigger=PropertyChanged 告诉Binding 在控件属性更改时更新视图模型属性。这看起来很傻,但你也可以将它设置为UpdateSourceTrigger=LostFocusTextBox.Text 默认为LostFocus,因为TextBox 的常见情况是用户输入了一段时间,但在他完成输入并将焦点更改为另一个控件之前,您真的不关心更新您的视图模型。更新 viewmodel 属性可能会产生很多副作用,因此如果每次 Text 更改时都更新绑定的 viewmodel 属性,在某些情况下,您可能会出现病态行为:每次用户键入一个字符时,都会产生很多大量代码开始运行,以至于 UI 陷入困境。因此LostFocus

这不是这个问题的主题,因为那不是TextBox。这是一个TextBlock,它根本无法更新源属性,因此该标志将不起作用。

顺便问一下,“黑”是什么意思?那是因为它显示在TextBlock 中吗?如果在显示它的 UI 中添加另一个位置,但新位置是一个实验室,会发生什么情况;你应该把它重命名为FilesProcessedBlckAndLbl吗?最好叫它FilesProcessedCount 并让视图模型不关心 UI 的功能。

【讨论】:

  • 艾德,感谢您的帮助。 “Blck”是块,是我工作的地方命名约定的保留。我试图使用“No code behind”,但可能把它带到了很远的地方。在模型中,我有一个循环来计算处理了多少项目,并且我试图在返回 ViewModel 之前从模型中更新它(FilesProcessedBlck),显然这样做很糟糕。
猜你喜欢
  • 2013-12-07
  • 2018-05-18
  • 2012-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-15
  • 2020-02-11
相关资源
最近更新 更多