Текстовый блок не обновляется при изменении свойства в модели
Мой текстовый блок не обновляется, обновите значение из моей модели. Если я обновлю текстовый блок в 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 ответ
var _p4LabelBatteryViewModel = new P4LabelBatteryViewModel();
_p4LabelBatteryViewModel.FilesProcessedBlck++; //xaml is never updated with this value.
Итак, ваш XAML должен иметь копию модели представления, если это TextBlock
когда-либо отображает то, что вы ожидаете в первую очередь. Но затем в этом методе вы создаете новый экземпляр того же класса viewmodel, устанавливаете для него свойство, а затем ничего не делаете с ним. Это выходит за рамки, и сборщик мусора съедает его в конце концов. Это никогда не был DataContext любого представления, где бы то ни было, поэтому, конечно, это не влияет на пользовательский интерфейс.
_p4LabelBatteryViewModel
является локальной переменной Никто за пределами этого метода никогда не видит его и даже не знает, что он существует. Если вы хотите изменить копию модели представления, которая фактически отображается в пользовательском интерфейсе, вы должны изменить ее экземпляр. Также, пожалуйста, не используйте префикс локальных переменных _
, По соглашению, начальное подчеркивание указывает на закрытое поле, принадлежащее классу. Лучше придерживаться этого соглашения, чтобы избежать путаницы.
Модель представления должна обновить свою собственную 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; "target" - это свойство элемента управления UI. UpdateSourceTrigger=PropertyChanged
говорит Binding
обновлять свойство viewmodel при каждом изменении свойства элемента управления. Это кажется глупым, но вы также можете установить его UpdateSourceTrigger=LostFocus
; TextBox.Text
по умолчанию LostFocus
потому что обычный случай с TextBox
в том, что пользователь печатает некоторое время, но вам действительно не нужно обновлять вашу модель представления, пока он не закончит печатать и не переключит фокус на другой элемент управления. Обновление свойства viewmodel может иметь много побочных эффектов, поэтому, если вы обновляете связанное свойство viewmodel каждый раз, когда Text
Изменения, в некоторых случаях вы можете закончить с патологическим поведением: каждый раз, когда пользователь вводит символ, весь код запускается в движение, настолько, что пользовательский интерфейс застревает. таким образом LostFocus
,
Это все не по теме для этого вопроса, потому что это не TextBox
, Это TextBlock
, который вообще не может обновить свойство источника, поэтому этот флаг не будет иметь никакого эффекта.
Кстати, что значит "Blck"? Это потому, что отображается в TextBlock
? Что произойдет, если добавить другое место в пользовательском интерфейсе, где оно показано, но новое - это лаба;; затем переименуйте его FilesProcessedBlckAndLbl
? Лучше позвонить FilesProcessedCount
и не позволяйте модели представления заботиться о том, что делает пользовательский интерфейс.