在模型中更改属性时,textblock不会更新

时间:2016-10-26 18:24:47

标签: c# wpf mvvm prism-6

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

1 个答案:

答案 0 :(得分:2)

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

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

_p4LabelBatteryViewModel是一个局部变量。除了那种方法之外没有人能够看到它甚至知道它存在。如果要更改实际显示在UI中的视图模型的副本,则必须更改该实例。另外,请不要使用_为本地变量添加前缀。按照惯例,前导下划线表示属于某个类的私有字段。坚持这个惯例是最好的,以避免混淆。

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

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=PropertyChangedBinding中没有任何用途。 &#34;来源&#34;绑定的是viewmodel属性; &#34;目标&#34;是UI控件属性。 UpdateSourceTrigger=PropertyChanged告诉Binding每当控件属性更改时都会更新viewmodel属性。这看起来很愚蠢,但您也可以将其设置为UpdateSourceTrigger=LostFocus; TextBox.Text默认为LostFocus,因为TextBox的常见情况是用户输入了一段时间,但您真的不关心更新您的视图模型,直到他完成输入和将焦点转移到另一个控件。更新viewmodel属性可能会产生很多副作用,因此如果每次Text更改时更新绑定的viewmodel属性,在某些情况下最终会出现病态行为:每次用户键入一个字符时,很多代码都被投入运动,以至于UI陷入困境。因此LostFocus

对于这个问题,这一切都是偏离主题的,因为那不是TextBox。它是TextBlock,根本无法更新源属性,因此该标志无效。

顺便说一句,&#34; Blck&#34;意思?这是因为它显示在TextBlock中吗?如果在UI中添加了另一个显示的位置会发生什么,但新的位置是labe;你应该重命名它FilesProcessedBlckAndLbl吗?最好将其称为FilesProcessedCount,并使视图模型远离关注UI所做的事情。