WPF MVVM Как предварительно заполнить текстовое поле с привязкой на ShowDialog ()? - PullRequest
0 голосов
/ 08 января 2020

У меня есть окно формы, которое я показываю с ShowDialog(), текстовые поля привязаны к свойствам в модели представления. Я открываю свой диалог следующим образом (упрощенная версия):

FilterWindowView wnd = new FilterWindowView();
FilterWindowViewModel fvm = new FilterWindowViewModel(licenseRecords) { wnd = wnd };
wnd.DataContext = fvm;
fvm.RestoreCurrentFilters();
if (wnd.ShowDialog() ?? false)
{
    //...
}

Свойства, заданные в моей форме, используются в качестве параметров фильтра, которые я сохраняю в классе stati c для извлечения для дальнейшего использования.

Я бы хотел, чтобы текстовые поля автоматически заполнялись текущим значением, сохраненным в этом классе c.

Мои свойства, связанные с текстовыми полями, выглядят так:

    private string _product;
    public string product
    {
        get { return _product; }
        set
        {
            if (_product == value)
                return;
            _product = value;
            Helper.product = value;
            if (value != "")
                chkProduct = true;
            OnPropertyChanged();
        }
    }

(я думаю, что может быть лучше переназначить производительность при проверке, но это другой вопрос ...) Моя проблема здесь в том, что если я устанавливаю значение (т.е. в конструкторе), значение устанавливается, но при вызове ShowDialog(), значение сбрасывается на "".

Также пытался вызвать метод после создания экземпляра виртуальной машины, но, как уже было сказано, этот сброс происходит при отображении окна (при вызове ShowDialog()) ...

Эта форма генерирует пользовательский объект, который я восстанавливаю на виртуальной машине dialogResult, поэтому wnd.Show() и затем установка на сохраненные значения для меня не вариант (наверное?).

Спасибо за любая помощь.

* 102 4 * РЕДАКТИРОВАТЬ Просмотр настолько прост, насколько это возможно, всего несколько ярлыков и текстовых полей с двухсторонней привязкой к ВМ.

<Window x:Class="LicenseManager.View.FilterWindowView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:LicenseManager.View"
    mc:Ignorable="d"
    Title="FilterWindowView" Height="306.412" Width="284.216">
<Grid>
    <CheckBox Content="Product" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" IsChecked="{Binding chkProduct}"/>
    <TextBox HorizontalAlignment="Left" Height="23" Margin="137,8,0,0" TextWrapping="Wrap" Text="{Binding product, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
    <CheckBox Content="Client" HorizontalAlignment="Left" Margin="10,38,0,0" VerticalAlignment="Top" IsChecked="{Binding chkClient}"/>
    <TextBox HorizontalAlignment="Left" Height="23" Margin="137,36,0,0" TextWrapping="Wrap" Text="{Binding client, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
    <CheckBox Content="Date After" HorizontalAlignment="Left" Margin="10,66,0,0" VerticalAlignment="Top" IsChecked="{Binding chkDateAfter}"/>
    <TextBox HorizontalAlignment="Left" Height="23" Margin="137,64,0,0" TextWrapping="Wrap" Text="{Binding dateAfter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
    <CheckBox Content="Date Before" HorizontalAlignment="Left" Margin="10,94,0,0" VerticalAlignment="Top" IsChecked="{Binding chkDateBefore}"/>
    <TextBox HorizontalAlignment="Left" Height="23" Margin="137,92,0,0" TextWrapping="Wrap" Text="{Binding dateBefore, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
    <CheckBox Content="Sbs__no" HorizontalAlignment="Left" Margin="10,122,0,0" VerticalAlignment="Top" IsChecked="{Binding chkSbsNo}"/>
    <TextBox HorizontalAlignment="Left" Height="23" Margin="137,120,0,0" TextWrapping="Wrap" Text="{Binding sbsNo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
    <CheckBox Content="Store__no" HorizontalAlignment="Left" Margin="10,150,0,0" VerticalAlignment="Top" IsChecked="{Binding chkStoreNo}"/>
    <TextBox HorizontalAlignment="Left" Height="23" Margin="137,148,0,0" TextWrapping="Wrap" Text="{Binding storeNo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
    <CheckBox Content="Workstation__no" HorizontalAlignment="Left" Margin="10,178,0,0" VerticalAlignment="Top" IsChecked="{Binding chkWorkstationNo}"/>
    <TextBox HorizontalAlignment="Left" Height="23" Margin="137,176,0,0" TextWrapping="Wrap" Text="{Binding workstationNo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
    <CheckBox Content="Comment" HorizontalAlignment="Left" Margin="10,206,0,0" VerticalAlignment="Top" IsChecked="{Binding chkWorkstationNo}"/>
    <TextBox HorizontalAlignment="Left" Height="23" Margin="137,204,0,0" TextWrapping="Wrap" Text="{Binding comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
    <Button Content="Apply" Command="{Binding apply}" HorizontalAlignment="Left" Margin="10,236,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>

РЕДАКТИРОВАНИЕ View Model class Helper - это мое состояние c class

    class FilterWindowViewModel : INotifyPropertyChanged
        {
            #region Attributes
            public Window wnd; // For dialog closer
            public List<LicenseRecordModel> list;
            public List<LicenseRecordModel> dialogResult;
            public event PropertyChangedEventHandler PropertyChanged;

            string tmpProduct;
            string tmpClient;
            string tmpDateAfter;
            string tmpDateBefore;
            string tmpSbsNo;
            string tmpStoreNo;
            string tmpWorkstationNo;
            string tmpComment;
            #endregion

            #region Properties
            //Properties and commands
        private string _comment;
        public string comment
        {
            get { return _comment; }
            set
            {
                if (_comment == value)
                    return;
                _comment = value;
                Helper.comment = value;
                if (value != "")
                    chkComment = true;
                OnPropertyChanged();
            }
        }


//...
        private DelegateCommand _apply;
        public DelegateCommand apply
        {
            get
            {
                return _apply ?? (_apply = new DelegateCommand(o => Apply(), o => true));
            }
        }
            #endregion

            #region Init
            public FilterWindowViewModel(IEnumerable<LicenseRecordModel> source)
            {
                tmpProduct = Helper.product;
                tmpClient = Helper.client;
                tmpDateAfter = Helper.dateAfter;
                tmpDateBefore= Helper.dateBefore;
                tmpSbsNo = Helper.sbsNo;
                tmpStoreNo = Helper.storeNo;
                tmpWorkstationNo = Helper.workstationNo;
                tmpComment = Helper.comment;
                list = new List<LicenseRecordModel>(source);
            }

            public void RestoreCurrentFilters()
            {
                product = tmpProduct;
                client = tmpClient;
                dateAfter = tmpDateAfter;
                dateBefore = tmpDateBefore;
                sbsNo = tmpSbsNo;
                storeNo = tmpStoreNo;
                workstationNo = tmpWorkstationNo;
                comment = tmpComment;
            }

            protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChangedEventHandler handler = PropertyChanged;

                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs(propertyName));
                }
            }
            #endregion

            private bool Accept(LicenseRecordModel lic)
            {
                var tmp = list;
                tmp = list.Where(x => 
                chkProduct ? x.Product.Contains(product) : true &&
                chkClient ? x.Client.Contains(client) : true &&
                chkProduct ? x.Product.Contains(product) : true &&
                chkProduct ? x.Product.Contains(product) : true &&
                chkProduct ? x.Product.Contains(product) : true &&
                chkProduct ? x.Product.Contains(product) : true &&
                chkProduct ? x.Product.Contains(product) : true
                ).ToList();
                return false;
            }

            #region Commands
            public void Apply()
            {
                var tmp = new List<LicenseRecordModel>(list);
                dialogResult = new List<LicenseRecordModel>(list);
                string message = "";
                if (chkProduct)
                {
                    dialogResult =tmp.Where(x => x.Product.Contains(product.ToUpper())).ToList();
                    tmp = dialogResult;
                }
                if (chkClient)
                {
                    dialogResult = tmp.Where(x => x.Client.Contains(client.ToUpper())).ToList();
                    tmp = dialogResult;
                }
                if (chkDateAfter)
                {
                    DateTime after;
                    if (chkDateBefore)
                    {
                        DateTime before;
                        if (DateTime.TryParse(dateAfter, out after))
                        {
                            if (DateTime.TryParse(dateBefore, out before))
                            {
                                dialogResult = tmp.Where(x => DateTime.ParseExact(x.CreationDate, "yyyy-MM-dd", null) <= after && DateTime.ParseExact(x.CreationDate, "yyyy-MM-dd", null) >= before).ToList(); ;
                                tmp = dialogResult;
                            }
                            else message += "'Date Before' is not a valid date (yyyy-mm-dd)";
                        }
                        else message += "'Date After' is not a valid date (yyyy-mm-dd)";
                    }
                    else if (DateTime.TryParse(dateAfter, out after))
                    {
                        dialogResult = tmp.Where(x => DateTime.ParseExact(x.CreationDate, "yyyy-MM-dd", null) >= after).ToList();
                        tmp = dialogResult;
                    }
                    else message += "'Date After' is not a valid date (yyyy-mm-dd)";
                }
                if (chkDateBefore)
                {
                    DateTime before;
                    if (DateTime.TryParse(dateBefore, out before))
                    {
                        dialogResult = tmp.Where(x => DateTime.ParseExact(x.CreationDate, "yyyy-MM-dd", null) <= before).ToList();
                        tmp = dialogResult;
                    }
                    else message += "'Date After' is not a valid date (yyyy-mm-dd)";
                }
                if (chkSbsNo)
                {
                    dialogResult = tmp.Where(x => x.SbsNo.Contains(sbsNo)).ToList();
                    tmp = dialogResult;
                }
                if (chkStoreNo)
                {
                    dialogResult = tmp.Where(x => x.StoreNo.Contains(storeNo)).ToList();
                    tmp = dialogResult;
                }
                if (chkWorkstationNo)
                {
                    dialogResult = tmp.Where(x => x.WorkstationNo.Contains(workstationNo)).ToList();
                    tmp = dialogResult;
                }
                if (chkComment)
                {
                    dialogResult = tmp.Where(x => x.Comment.ToUpper().Contains(comment.ToUpper())).ToList();
                    tmp = dialogResult;
                }
                if (message != "")
                {
                    MessageBox.Show(message);
                }
                else
                {
                    DialogCloser.SetDialogResult(wnd, true);
                }
            }
            #endregion
        }

EDIT : Обновлен вид с привязками, установленными на TwoWay (решено)

Ответы [ 2 ]

4 голосов
/ 15 января 2020

Несколько проблем:

1) Поскольку вы хотите отправить значения Helper (просмотр модели по умолчанию) на TextBox.Text, привязка должна быть не менее OneWay (источник -> цель) , Поскольку вы также хотите отправить входные данные из TextBox.Text в модель представления, привязка становится TwoWay (source <-> target).

Поскольку TwoWay является значением по умолчанию Binding.Mode для свойства TextBox.Text, вы можете безопасно удалить Binding.Mode из выражения привязки:

<TextBox Text="{Binding product, UpdateSourceTrigger=PropertyChanged}" />

2) Вы не делаете нужен класс Helper для хранения данных. Просто добавьте свойство в класс, который создает экземпляр диалогового окна.
Также вам больше не нужен метод RestoreCurrentFilters() и куча полей tmp... в вашей модели представления.

public partial class MainWindow
{
  // Shared and reused view model instance
  private FilterWindowViewModel DialogViewModel{ get; set; }

  public MainWindow()
  { 
    this.DialogViewModel = new FilterWindowViewModel();
  }

  private void ShowDialog()
  {
    var dialog = new FilterWindowView() { DataContext = this.DialogViewModel };
    if (dialog.ShowDialog() ?? false)
    {
      //...
    }
  }
}

FilterWindowViewModel.cs

public class FilterWindowViewModel 
{
  private string _product;
  public string Product
  {
    get => _product; 
    set
    {
      if (_product == value)
        return;

      _product = value;

      this.chkProduct = !string.IsNullOrWhiteSpace(value);
      OnPropertyChanged();
    }
  }
}

3) Модель представления не должна иметь ссылку на Window.
4) Предпочитать данные Проверка. Просто внедрите INotifyDataErrorInfo. * * Пример тысяча тридцать четыре

0 голосов
/ 14 января 2020

Когда вы говорите «при вызове ShowDialog (), значение сбрасывается на« »», это потому, что привязки TextBox используют Mode=OneWayToSource. Изменение в текстовом поле обновит свойство VM, но не наоборот. Когда представление будет создано, текстовые поля не будут заполнены значениями свойств виртуальной машины, которые вы задали в конструкторе, поэтому они останутся пустыми.

Кроме того, эти значения текстовых полей (пустые строки) фактически обновятся обратно в свойствах виртуальной машины при первом создании представления, что приводит к поведению, которое вы видите. Удалите режим привязки из каждого текстового поля, и он должен работать нормально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...