S
S
Space Purr2019-03-25 19:30:40
WPF
Space Purr, 2019-03-25 19:30:40

How to dynamically change the value of a TextBox if the Binding goes through a Dictionary?

Hello.
A little preface.
I am writing an application that works with KOMPAS-3D CAD system via Kompas Api.
The application processes a package of drawings, filling in the stamp for all drawings at once according to a specific template and saves all drawings in PDF format.
The application has a MainWindow and several Pages, each of which is associated with its own ViewModel in XAML

<Page.DataContext>
        <ViewModels:StampViewModel/>
    </Page.DataContext>

Switch Page via HamburgerMenu.
In Page Stamp.xaml, a drawing stamp is drawn, which has about 60 TextBoxes to fill and save their values.
5c98f63dac1fa007118350.jpeg
Each stamp cell has a specific index in Kompas Api, by which it can be written to the drawing.
5c98f78b48e51492122252.png
Now closer to the heart of the matter.
I implemented a Singleton in which I store a Dictionary with the keys I need
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",""},
            };
        }
    }

The Dictionary initially only has keys so that it can be used via Binding.
I also have a StampViewModel in which I get a Singleton object and work through it with my 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;
            }
        }
    }

...and a few lines of 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}"/>

Thus, the values ​​of the TextBox are associated with the values ​​by key from the Dictionary.
The screenshot above also has a Clear button that calls the ClearDictionary() method and recreates the Dictionary again.
So the problem is that the TextBox is not cleared dynamically, but only if you change the Page and go back. You can see it in the gif below. If the Clear button is not pressed, then all data is loaded from the singleton, and when the button is pressed, the data is deleted only after switching between pages.
zd1936ofj7e8tpy1s2svrpijrzu.gif
How to implement this task correctly so that the boxes are cleared dynamically, and in general the approach to processing 60 boxes? I could not think of a more compact method than using a dictionary.
~~~~~~~~~~
If I may, just one more question that worries me
Why in the Properties of the TextBoxes variable, which is in the StampViewModel, you do not need to write PropertyChanged, because in the Properties for changing the page, Binding does not work without this, but here everything works fine.
Variable for Binding TextBox
public Dictionary<string, string> TextBoxes
        {
            get => stampDictionary.TextBoxes;
            set
            {
                stampDictionary.TextBoxes = value;
                //OnPropertyChanged();
            }
        }

Variable from MainViewModel to Binding Source in Frame
public string CurrentPage
        {
            get => currentPage;
            set
            {
                currentPage = value;
                OnPropertyChanged();
            }
        }

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

Thank you.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
F
Foggy Finder, 2019-03-25
@SpacePurr

To inform the view (View) about the change in the value of a particular property from the VM, you need to pass its name as a parameter: Directly in the properties themselves, you can see that the call is in progress without passing parameters: The fact is that in a typical implementation, the property name is retrieved using the CallerMemberName attribute :

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

It doesn't have to be done in set. A property may not have a public setter, or may not have a setter at all. Or if the property depends on two others - for example, to automatically display the sum of the values ​​that the user must enter.
In your case with TextBoxes you don't use a setter - you can even remove it altogether.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question