Текстовый блок не обновляется при изменении свойства в модели

Мой текстовый блок не обновляется, обновите значение из моей модели. Если я обновлю текстовый блок в 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 и не позволяйте модели представления заботиться о том, что делает пользовательский интерфейс.

Другие вопросы по тегам