SpacePurr
@SpacePurr
c#, wpf

Как динамически менять значение TextBox, если Binding идет через Dictionary?

Здравствуйте.

Немного предисловия.
Я пишу приложение, которое работает с CAD системой КОМПАС-3D через Kompas Api.
Приложение обрабатывает пакет чертежей, заполняя штамп у всех чертежей сразу по определенному шаблону и сохраняет все чертежи в PDF формате.

Приложение имеет MainWindow и несколько Page, каждый из которых связан со своим ViewModel в XAML
<Page.DataContext>
        <ViewModels:StampViewModel/>
    </Page.DataContext>


Переключаются Page через HamburgerMenu.

В Page Stamp.xaml нарисован штамп чертежа, который имеет порядка 60 TextBox для заполнения и сохранения их значений.
5c98f63dac1fa007118350.jpeg

Каждая ячейка штампа имеет определенный индекс в Kompas Api, по которому ее можно записать в чертеж.
5c98f78b48e51492122252.png

Теперь ближе к сути вопроса.
Я реализовал Singleton, в котором храню Dictionary с нужными мне ключами
class StampDictionary
    {
        private static StampDictionary instance;

        private Dictionary<string, string> textBoxes;
        public Dictionary<string, string> TextBoxes
        {
            get => textBoxes;
            set
            {
                textBoxes = value;
            }
        }

        public StampDictionary()
        {
            ClearDictionary();
        }

        public static StampDictionary GetInstance()
        {
            if (instance == null)
                instance = new StampDictionary();
            return instance;
        }

        public void ClearDictionary()
        {
            TextBoxes = new Dictionary<string, string>()

            {
                {"1",""},{"2",""},{"3",""},{"5",""},{"6",""},{"7",""},{"8",""},{"9",""},
                {"10",""},{"19",""},
                {"21",""},{"22",""},
                {"31",""},{"32",""},
                {"110",""},{"111",""},{"112",""},{"113",""},{"114",""},{"115",""},
                {"120",""},{"121",""},{"122",""},{"123",""},{"124",""},{"125",""},
                {"130",""},{"131",""},{"132",""},{"133",""},{"134",""},{"135",""},
                {"140",""},{"141",""},{"142",""},{"143",""},
                {"150",""},{"151",""},{"152",""},{"153",""},
                {"160",""},{"161",""},{"162",""},{"163",""},
                {"170",""},{"171",""},{"172",""},{"173",""},
                {"180",""},{"181",""},{"182",""},{"183",""},
                {"200",""},{"201",""},{"230",""},{"231",""},
            };
        }
    }

Dictionary изначально имеет только ключи, чтобы можно было использовать его через Binding.

Также я имею StampViewModel, в котором получаю объект Singleton и работаю через него со своим Dictionary.
class StampViewModel : ViewModelBase
    {
        public ICommand MyCommand { get; set; }

        StampDictionary stampDictionary = StampDictionary.GetInstance();

        public Dictionary<string, string> TextBoxes
        {
            get => stampDictionary.TextBoxes;
            set
            {
                stampDictionary.TextBoxes = value;
            }
        }

        public StampViewModel()
        {
            MyCommand = new Command(ExecuteMethod, CanExecuteMethod);
        }

        public bool CanExecuteMethod(object parameter)
        {
            return true;
        }
        public void ExecuteMethod(object parameter)
        {
            switch (parameter)
            {
                case "Clear":
                    stampDictionary.ClearDictionary();
                    break;
            }
        }
    }


...и несколько строк из XAML
<TextBox Grid.Column="2" Grid.Row="5" Text="{Binding TextBoxes[110], Mode=TwoWay}"/>
<TextBox Grid.Column="3" Grid.Row="5" Text="{Binding TextBoxes[120], Mode=TwoWay}"/>
<TextBox Grid.Column="4" Grid.Row="5" Text="{Binding TextBoxes[130], Mode=TwoWay}"/>


Таким образом значения TextBox связаны со значениями по ключу из Dictionary.

На скрине выше также есть кнопка Clear, которая вызывает метод ClearDictionary() и пересоздает Dictionary заново.

Так вот проблема в том, что TextBox очищается не динамически, а только если сменить Page и вернуться обратно. Это можно увидеть на гифке ниже. Если кнопку Clear не нажимать, то все данные подгружаются из синглтона, а по нажатию кнопки, данные удаляются только после переключения между страницами.

zd1936ofj7e8tpy1s2svrpijrzu.gif

Как правильно реализовать данную задачу, чтобы боксы очищались динамически, да и вообще подход к обработке 60 боксов? Метода компактнее, чем через словарь я придумать не смог.

~~~~~~~~~~
Если позволите,сразу еще один вопрос, который меня волнует
Почему в Свойствах переменной TextBoxes, которая находится в StampViewModel, не нужно прописывать PropertyChanged, ведь в Свойствах для смены страницы без этого Binding не работает, а здесь все работает прекрасно.

Переменная для Binding TextBox
public Dictionary<string, string> TextBoxes
        {
            get => stampDictionary.TextBoxes;
            set
            {
                stampDictionary.TextBoxes = value;
                //OnPropertyChanged();
            }
        }


Переменная из MainViewModel для Binding Source во Frame
public string CurrentPage
        {
            get => currentPage;
            set
            {
                currentPage = value;
                OnPropertyChanged();
            }
        }

<Frame 
            Margin="50,0,0,0"
            NavigationUIVisibility="Hidden"
            Source="{Binding CurrentPage}">
        </Frame>


Спасибо.
  • Вопрос задан
  • 877 просмотров
Решения вопроса 1
FoggyFinder
@FoggyFinder
Чтобы сообщить представлению (View) об изменении значения конкретного свойства из VM нужно передать его название в виде параметра:

OnPropertyChanged(nameof(TextBoxes));

Непосредственно в самих свойствах вы можете увидеть что идет вызов без передачи параметров:

OnPropertyChanged();

Дело в том, что в типичной реализации имя свойства извлекается при помощи атрибута CallerMemberName:

public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string prop = "")
{
// ...
}


Это не обязательно делать в set. У свойства может не быть открытого сеттера или не быть сеттера вообще. Или если свойство зависит от двух других - например, для автоматического отображения суммы значений, которые должен вводить пользователь.

В вашем случае с TextBoxes вы не используете сеттер - его можно даже совсем убрать.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы