2016-10-26 5 views
0

Мой текстовый блок не обновляется, обновляет значение из моей модели. Если я обновляю текстовый блок в ViewModel, он работает, поэтому мои привязки кажутся правильными. Я считаю, что проблема заключается в том, как я обновляю ее в модели, но я не уверен, почему и мои наблюдаемые коллекции обновляются только потому, что я передаю значения назад и вперед, не уверен, что это хорошая стратегия 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> 

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 не обновляется.

+0

Похож на проблему с вашим .DataContext. Похоже, что у вас нет правильного назначения, поэтому ваш TextBlock указывает на один экземпляр «P4LabelBatteryViewModel», в то время как вы создаете второй экземпляр в вашем коде «ObservableCollection». – Rachel

ответ

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

ОК, так что ваш XAML должен иметь копию ViewModel, если это когда-либо TextBlock показывает, что вы ожидаете в первую очередь. Но затем в этом методе вы создаете новый экземпляр того же класса viewmodel, устанавливаете на нем свойство, а затем вы ничего не делаете с ним. Он выходит из сферы действия, и сборщик мусора съедает его в конце концов. Это никогда не было DataContext любого вида в любом месте, поэтому, конечно, это не влияет на пользовательский интерфейс.

_p4LabelBatteryViewModel - локальная переменная. Никто из этого метода никогда не видит его или даже не знает, что он существует. Если вы хотите изменить копию модели просмотра, которая фактически отображается в пользовательском интерфейсе, вам необходимо изменить , что экземпляр. Кроме того, не рекомендуется префикс локальных переменных _. По соглашению ведущее подчеркивание указывает частное поле, принадлежащее классу. Лучше придерживаться этого соглашения, чтобы избежать путаницы.

Viewmodel должен обновить свою собственную собственность FilesProcessedBlck. В любом случае не рекомендуется, чтобы модель отвечала за сохранение состояния viewmodel. Это проблема 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; «target» - это свойство управления пользовательским интерфейсом. UpdateSourceTrigger=PropertyChanged сообщает Binding, чтобы обновить свойство viewmodel всякий раз, когда изменяется свойство управления. Это кажется глупым, но вы также можете установить его на UpdateSourceTrigger=LostFocus; TextBox.Text по умолчанию LostFocus, потому что обычный случай с TextBox заключается в том, что пользователь на некоторое время набирает время, но вы действительно не заботитесь об обновлении своей модели просмотра до тех пор, пока он не закончит печатать и не переключит фокус на другой элемент управления.Обновление свойства viewmodel может иметь множество побочных эффектов, поэтому, если вы обновляете свойство boundmodel bound каждый раз, когда изменяется Text, в некоторых случаях вы можете столкнуться с патологическим поведением: каждый раз, когда пользователь вводит символ, бросается в движение, настолько, что пользовательский интерфейс борется. Таким образом, LostFocus.

Это не по теме для этого вопроса, потому что это не TextBox. Это TextBlock, который вообще не может обновить исходное свойство, так что флаг не будет иметь никакого эффекта.

Кстати, что означает «Блэк»? Это потому, что отображается в TextBlock? Что произойдет, если добавить другое место в пользовательском интерфейсе, где он показан, но новый - это labe ;; если вы затем переименуете его FilesProcessedBlckAndLbl? Лучше назвать это FilesProcessedCount и оставить viewmodel вне бизнеса заботы о том, что делает пользовательский интерфейс.

+0

Эд, спасибо за помощь. «Блэк» - это блок, состоящий из соглашения об именах в месте, где я работал. Я пытался использовать «Без кода», но, возможно, перенес его далеко. В модели у меня есть цикл, который подсчитывает, сколько элементов обрабатывается, и я пытался обновить это (FilesProcessedBlck) из Модели до того, как вернуться к ViewModel, видимо, это плохо. – coolercargo