0

我的文本块没有更新更新我的模型中的值。如果我更新 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 没有被更新。

4

1 回答 1

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

好的,因此您的 XAML 必须具有视图模型的副本,如果它TextBlock首先显示您期望的内容。但是在这个方法中,你创建了同一个视图模型类的一个新实例,在它上面设置了一个属性,然后你就什么也不做了。它超出了范围,垃圾收集器最终吃掉了它。它从来都不是任何视图的 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<T>. 你可能永远没有任何理由给它其他任何东西,但如果你在代码中养成这种灵活性的习惯,它就会得到回报。

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

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

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

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

于 2016-10-26T18:36:47.673 回答