2016-10-26 293 views
0

我的文本块未更新从我的模型更新值。如果我更新ViewModel中的文本块,它会起作用,所以我的绑定似乎是正确的。我相信问题是我在模型中更新它的方式,但我不确定为什么我的observableCollection也只是更新,因为我来回传递值并不确定这是不错的MVVM策略。textblock在属性更改时未更新

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> 

视图模型部分:

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); 
     } 

    }   

} 

Model部分:

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没有被更新。

+0

看起来像'.DataContext'问题。看起来你没有正确指定它,所以当你在你的'ObservableCollection'代码中创建第二个实例时,你的TextBlock指向'P4LabelBatteryViewModel'的一个实例。 – Rachel

回答

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

好了,你的XAML必须有视图模型的副本,如果TextBlock曾经显示您首先会发生什么。但是,在这个方法中,你创建了一个相同viewmodel类的新实例,在它上面设置一个属性,然后你就不用做任何事情了。它超出范围,垃圾收集器最终会吃掉它。它在任何地方都不是任何视图的DataContext,所以它当然对UI没有任何影响。

_p4LabelBatteryViewModel是一个局部变量。除此之外,没有人会看到它,甚至不知道它存在。如果您想更改实际在UI中显示的视图模型的副本,则必须更改其实例。另外,请不要用_前缀局部变量。按照惯例,前导下划线表示属于一个类的私人字段。为了避免混淆,最好遵守这一惯例。

视图模型应该更新自己的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=PropertyChanged不会起任何作用在Binding。绑定的“源”是viewmodel属性; “目标”是UI控件属性。 UpdateSourceTrigger=PropertyChanged告诉Binding每当control属性更改时更新viewmodel属性。这似乎很愚蠢,但你也可以将它设置为UpdateSourceTrigger=LostFocus; TextBox.Text默认为LostFocus,因为通常情况下TextBox是用户输入了一段时间,但您完全不关心更新视图模型,直到他完成键入并将焦点更改为其他控件。更新viewmodel属性可能会产生很多副作用,所以如果每次更改绑定的viewmodel属性,在某些情况下,最终会出现病态行为:每当用户键入一个字符时,会有大量代码被投入运行,太多以至于UI陷入泥潭。因此LostFocus

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

顺便说一句,“Blck”是什么意思?那是因为它显示在TextBlock?如果在显示UI的地方添加另一个地方会发生什么,但新的地方是一个labe ;;你应该重命名它FilesProcessedBlckAndLbl?最好称之为FilesProcessedCount,并保持viewmodel不在乎关注UI的功能。

+0

埃德,感谢您的帮助。 “Blck”是阻止,从我工作的地方命名约定。我试图使用“没有代码背后”,但可能会把它带到很远。在模型中,我有一个循环来计算处理了多少项,并且在返回ViewModel之前我试图从模型中更新(FilesProcessedBlck),显然这是不好的。 – coolercargo

相关问题