Clear values loaded from a JSON file in a C# application - c#

I have a C# very big C# application with a lot of values that are saved in a JSON file. At the very start, I can either do it fresh (i.e: choose new values as I enter in the values in the textboxes etc) or load an existing JSON file. There are no problems with either of that.
However, now what I want to be able to do is that if I load in an existing JSON file with said values, and if I go back then those values should be cleared up. Let me demonstrate all this more with examples.
So I have two modes- fresh and update. In fresh, I type in those values manually however in update, you are asked to upload a JSON file and then those values are loaded in their respective text boxes, check boxes etc.
As it stands now, if I have loaded in a JSON file and then I click "Back" to go to fresh mode, the values are not reset and my application loads in the values from the JSON file. I want to be able to clear those values and reset them. I don't know how to achieve this.
In the "browse" button where the user loads up the JSON file, I have this code:
private void Browse_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog
{
DefaultExt = ".json",
Filter = "JSON Files (*.json)|*.json"
};
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
Configs.ConfigPath = dlg.FileName;
jsonFile.Text = dlg.FileName;
string userJson = File.ReadAllText(Configs.ConfigPath);
try
{
var json = JsonConvert.DeserializeObject<AppConfigs>(userJson);
try
{
CopyNotNulls(json, Configs.Default);
}
catch (Exception error)
{
MessageBox.Show(error.ToString());
}
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
}
For the xaml of the text box where you load in the json file, I have this TextChanged event arg and if I manually remove what the user has loaded and delete the text in that text box, then that works fine. But I want it done so that whenever I go back from that page, it resets when I go back from the update page to fresh page.

If I understand the process of your application correctly you are loading the json file into an objet and the controls that display the data are bound to the object properties, right? the only thing you have to do to get rid of those values is to get a new object if you go the fresh route. Just do:
var json = new AppConfigs();
alternatively, if you want to keep some of the values you'd have to reset them, for example on the AppConfigs object you can add a public method that clears the fields you want to get rid of. That would look like this:
public class AppConfigs
{
public string stringProp { get; set; }
public bool boolProp { get; set; }
public int intProp { get; set; }
public AppConfigs()
{
// default values here
// or just call Clear();
stringProp = "";
boolProp = false;
intProp = 0;
}
public void Clear()
{
stringProp = "";
boolProp = false;
intProp = 0;
}
}
then you could call it on your button click:
json.Clear();

Related

In WPF, how do I change the source of an image programatically? [duplicate]

This question already has answers here:
How to load image to WPF in runtime?
(2 answers)
Closed 1 year ago.
I have a custom control with a default image that I want to change based on which iteration of the control it is. For example, I have one for "F1" and "NumLock" and so on. In the constructor of the control, I have this:
public FixerBox(Dictionary<string,string> deets)
{
InitializeComponent();
btnOff();
this.FixerTitle.Text = deets["Title"];
this.FixerDesc.Text = deets["Description"];
this.FixerTags.Text = deets["Tags"];
this.FixerImg.Source = new BitmapImage(new Uri(deets["Img"], UriKind.Relative));
}
The bitmap stuff was based on another answer and produces this:
Below is the control itself showing that it's correctly getting the title, tags, and description, but the image is bunk (on the left side, that thin grey line is the border that should be around the image).c#
If I was using HTML/CSS, I could right-click the image to see what exactly its properties are, but I don't know how to get that kind of information using WPF. The best I could manage was in the top area is a status window where I've manually printed a "Tostring" output of the first controls image source data. Near as I can tell, it's all correct, but there's no actual image there. Every subsequent control has the same output (one thin line where the image should be).
EDIT Per comments, here is some more of the information. The main XAML file loads up the controls like so in its constructor:
public partial class MainWindow : Window
{
private Fixers fixers = new Fixers();
// This is the custom control consisting mostly of various boxes
private Dictionary<string,FixerBox> fixerBoxes = new Dictionary<string, FixerBox> { };
public MainWindow()
{
InitializeComponent();
var fixNames = fixers.FixerNames();
foreach (string key in fixNames)
{
fixerBoxes[key] = new FixerBox(fixers.GetFix(key));
FixersArea.Children.Add(fixerBoxes[key]);
}
StatusBox.Text += fixerBoxes["F1"].FixerImg.Source.ToString();
}
}
The fixers variable is of class Fixers which consists of the below (abbreviated to show just the F1 function for brevity):
class Fixers
{
private string ClearWS(string str)
{
var first = str.Replace(System.Environment.NewLine, "");
return first.Replace("\t", "");
}
// Loads registry functions
private Regis regStuff = new Regis();
// Loads preferences from the file
private Prefs prefs = new Prefs();
// A timer to make sure the system behaves
private Timer watcher;
// Watcher action toggles
private bool watchNumL = false;
// Translation array from fix shortname to various data about them
private Dictionary<string, Dictionary<string, string>> fixers = new Dictionary<string, Dictionary<string, string>>
{
["F1"] = new Dictionary<string,string> {
["PrefName"] = "KillF1UnhelpfulHelp",
["Img"] = #"/graphics/F1key.png",
["Title"] = #"Diable F1 ""Help"" function",
["Description"] = #"
Have you ever hit the F1 key by accident and had a distracting and unhelpful window or webpage open as a result?
Windows set the F1 key to a generic help function that basically never helps and always gets in the way.
Enable this control to disable that obnoxious design choice. Note that some programs still respond to F1 on their own accord,
but this will stop the default Windows behavior in things like Windows Explorer at least.
",
["Tags"] = "#Keyboard,#Rage"
},
};
public Fixers()
{
// The readability hack above with multi-line strings introduces a bunch of extra whitespace. Let's clear that out
foreach (var fixKey in fixers.Keys)
{
fixers[fixKey]["Description"] = ClearWS(fixers[fixKey]["Description"]);
}
}
public List<string> FixerNames()
{
return fixers.Keys.ToList();
}
public bool IsFixed(string which)
{
// If we're watching, it's fixed
if ("NumL" == which) return watchNumL;
// For anything registry related
return regStuff.IsFixed(which);
}
public Dictionary<string,string> GetFix(string which)
{
return fixers[which];
}
}
if you use binding, you can create in your ViewModel a string, in which is stored the path of your image, then you can easily change programatically its path.
Then in XAML just bind image's source to the string.
In my case I have a list of objects, with the property `ImageName' :
<Image Source="{Binding DataContext.SelectedMacro.ImageName,
RelativeSource={RelativeSource AncestorType=Window}}"/>

Is there a standard way to reference the same object between classes?

When I search this question, all of the answers I've seen only talk about handling an object within the same class but I need to handle the same data between classes.
I'm building an outlook addin which uses three classes to make up the key components of my programme:
ThisAddin - the default class created with the MS VS template, I'm using this class to store all of my methods, enums, data stores etc..
Ribbon - my outlook Ribbon containing a button to initiate a new enquiry form. Within the button_click is also a code to save relevant attachments from a selected email to a specified filepath.
NewEntry - a winform dialogue initiated when the ribbon button is clicked, used to create new enquiries.
I also have a class called NewSearchQuery which I was hoping to use as a datastore for all the relevant aspects of a new enquiry.
current logic goes like this - user presses button in the ribbon, a new object (referenced as Temp) is called and known data for some parameters are filled. Winform is opened and user fills in some more required data. On form submit, that data is added to the object metadata, a reference number is generated from a database, a file path is created using the reference number and all this is again added to the object metadata. Winform dialog closes and the ribbon saves the selected email attachments to the specified filepath stored within the object. Now all the object metadata can be sent to the enquiry database as a new enquiry.
Here's the code:
public enum ContractType
{
Searches, //there are other values in my code but they don't need to feature here
}
public class NewSearchQuery
{
public string Name, Location, SearchType, Path;
public int RefNum;
public bool Paid;
public ContractType Contract;
}
public partial class Ribbon
{
private void button1_Click(object sender, RibbonControlEventArgs e)
{
NewSearchQuery Temp = new NewSearchQuery();
Temp.Contract = ContractType.Searches;
var NewEntry = new NewEntry(Convert.ToString(Temp.Contract));
NewEntry.ShowDialog();
//wait until the NewEntry Dialogue and associated methods close and then run the below save attachments method:
var m = e.Control.Context as Inspector;
var mailitem = m.CurrentItem as MailItem;
mailitem.SaveAs(Temp.Path + #"\Initial_Contact.msg");
if (mailitem != null)
{
if (mailitem.Attachments.Count > 0)
{
foreach (Attachment item in mailitem.Attachments)
{
string[] extensionsArray = { ".jpg", ".jpeg", ".gif", ".png", ".tiff", ".tif", ".eps", ".bmp", ".vcf" };
if (!extensionsArray.Any(item.FileName.Contains))
{
item.SaveAsFile(Path.Combine(Temp.Path, item.FileName));
}
}
}
else
{
MessageBox.Show($"Operation Complete. Enquiry number {Temp.RefNum}. This email doesn't have any attachments.");
}
}
MessageBox.Show($"Operation Complete, Enquiry number {Temp.RefNum}.");
}
}
public partial class NewEntry : Form
{
public NewEntry(string ContractType)
{
InitializeComponent();
}
private void Create_Click(object sender, EventArgs e)
{
//here are the variables I would like to tie into the Temp object created in Ribbon
Temp.Name = Convert.ToString(Companies.SelectedItem);
Temp.Location = Convert.ToString(SearchLocation.Text);
Temp.SearchType = Convert.ToString(Search.SelectedItem);
Temp.Paid = Paid.Checked;
if (Temp.Name == "" || Location == "" || SearchType == "")
{
MessageBox.Show("Please ensure you have filled in all the required fields (*) before proceeding", "ERROR: insufficient info");
}
else
{
Temp.RefNum = ThisAddIn.FindIdNum();
Temp.Path = ThisAddIn.CreateFilePath(Temp.RefNum);
MessageBox.Show(Convert.ToString(d));
this.Close();
}
}
}
How can I reference the same object from both the Ribbon and NewEntry classes to keep all my required data centralised?
It looks like you don't need to actually share and you only want NewEntry to give you a NewSearchQuery when it completes.
That is pretty easy just add a method on NewEntry like this:
public NewSearchQuery GetEntry()
{
// make a new NewSearchQuery
var q = new NewSearchQuery();
// set its values from the form eg
q.Name = Convert.ToString(Companies.SelectedItem);
return q;
}
Then in the ribbon just do this after the ShowDialog:
var q = NewEntry.GetEntry();
So the idea is that the NewSearchQuery is always created by the form.
If you want a 2 way thing, create the NewSearchQuery first, then pass to the form using a similar method that initializes the form from the values.

Win 8.1 SearchBox SuggestionsRequested

I got an userControl that contains a searchBox.
This UserControl is inside another one.
I got a strange behavior while i'm searching, because the suggestionCollection works in a strange way.
Example :
in the searchBox i write something all works perfectly, if i choose the item it also works.
But if i try to use backspace (after the choose) i got no suggestion.
I cannot understand why it doesn't work.
That's the code
//var deferral = args.Request.GetDeferral(); //it seems to not influence the behavior
var suggestionCollection = args.Request.SearchSuggestionCollection;
try
{
TransporterExt tr_search = new TransporterExt();
//queryText is a string inserted in the searchBox
if (string.IsNullOrEmpty(queryText)) return;
tr_search.name = queryText;
suggested.Clear(); //that's a collection..
//just a search that return a collection of objects TransporterExt
querySuggestions = await TransporterService.Search_StartsWith(tr_search);
if (querySuggestions.Count > 0)
{
int i = 0;
foreach (TransporterExt tr in querySuggestions)
{
string name = tr.name;
string detail = tr.trId.ToString();
string tag = i.ToString();
string imageAlternate = "imgDesc";
suggestionCollection.AppendResultSuggestion(name, detail, tag, imgRef, imageAlternate);
this.suggested.Add(tr);
i++;
}
}
}
catch (System.ArgumentException exc)
{
//Ignore any exceptions that occur trying to find search suggestions.
Debug.WriteLine(exc.Message);
Debug.WriteLine(exc.StackTrace);
}
//deferralComplete(); //it seems to not influence the behavior
The problem is that: all the variables have the right value, but the suggestion panel appears only if i make a particular search: it appears when i change the first letter of search, or after an wrong seach
What appends when i make a search
What appends if i use the backspace, and i what i want to fix
As i said, all works perfectly, after the "backspace" action the suggestionCollection got the right value...but the panel is missing.
Could someone help me?
You can use SearchBox and SuggestionRequested event to fire the event when type on the SearchBox. I will show an Example
<SearchBox x:Name="SearchBoxSuggestions" SuggestionsRequested="SearchBoxEventsSuggestionsRequested"/>
and write the SearchBoxEventsSuggestionsRequested handler in the code behind
private void SearchBoxEventsSuggestionsRequested(object sender, SearchBoxSuggestionsRequestedEventArgs e)
{
string queryText = e.QueryText;
if (!string.IsNullOrEmpty(queryText))
{
Windows.ApplicationModel.Search.SearchSuggestionCollection suggestionCollection = e.Request.SearchSuggestionCollection;
foreach (string suggestion in SuggestionList)
{
if (suggestion.StartsWith(queryText, StringComparison.CurrentCultureIgnoreCase))
{
suggestionCollection.AppendQuerySuggestion(suggestion);
}
}
}
}
You can add the keyword to SuggestioList, and it will show in the dropdown when you type on the Searchbox.
Create the SuggestionList
public List<string> SuggestionList { get; set; }
initialize the list
SuggestionList = new List<string>();
and add keywords to the list
SuggestionList.Add("suggestion1");
SuggestionList.Add("suggestion2");
SuggestionList.Add("suggestion3");
SuggestionList.Add("suggestion4");
SuggestionList.Add("Fruits");
Thanks.

How to save a dynamic button permanently even when the machine is restarted

i have made a form with textbox and a save button in visual studio C#, entering text in textbox and clicking save creates a dynamic button on the other form in a vertical flowlayout panel,but when i re-run my application with a new text in the textbox,or restart my application then the previous button is lost, so tell me some logic or code that how can i save that dynamic button permanently in flowlayout panel and when new text is saved it creates another button below that of previously created one and so on.
For saving something done at the run-time, you either have to use a file, or use the Application Settings. A good reference about application settings can be found here on MSDN.
You can create a setting of a type like ButtonsList (which you have to write a class for) to store the button created. I said ButtonsList considering that you want to save more properties of each button. If you don't need to save anything else but the caption, you can set that property to be a string array.
Also, a very important thing, is that after the Save button is clicked, you have to call
Properties.Settings.Default.Save();
to keep the saved data while your application is not on.
Steps:
In Visual Studio, click PROJECT menu item.
Click <project-name> Properties item.
In the opened window, go to Settings on the left-side pane.
Click Setting in the table in the middle of the window, and type in the name of the setting that you want to create (e.g dynamicButtons).
Click on string drop-down, and choose System.Colletions.Specialized.StringCollection.
Go to your program and in the Save click event type:
Properties.Settings.Default.dynamicButtons.Add("button1_caption");
Properties.Settings.Default.Save();
Below is the code for a simple collection of ButtonInfos called ButtonsCollection:
class ButtonInfo
{
public string Caption { get; set; }
public Point Location { get; set; }
public Size ButtonSize { get; set; }
public ButtonInfo(string caption, Point location, Size size )
{
this.Caption = caption;
this.Location = location;
this.ButtonSize = size;
}
}
class ButtonsCollection : System.Collections.CollectionBase
{
public void Add(ButtonInfo bi)
{
List.Add(bi);
}
public void Remove(int index)
{
if (index > Count - 1 || index < 0)
{
System.Windows.Forms.MessageBox.Show("Index not valid!");
}
else
{
List.RemoveAt(index);
}
}
public ButtonInfo Item(int index)
{
return (ButtonInfo)List[index];
}
}
Since the visual designer for Settings in Visual Studio does not allow you to use custom type settings, you will have to do some manual work. You will find more about creating these custom settings here, on MSDN.
Hope my effort is not useless :)
You're going to want to save the information you need to recreate the button (maybe a label, the position or order) to a configuration file of some form. When you start up the application, check if the file exists. If it does, read it back in and then recreate your buttons.

Listing a table of folders using C#

I want to mimic the functionality of the following image using Visual C#:
This I know is not a textbox or a combobox or a richtext (Maybe).
I managed to get the add function, where I get directories and I can select them:
private void button8_Click(object sender, EventArgs e)
{
this.folderBrowserDialog1.ShowNewFolderButton = false;
this.folderBrowserDialog1.RootFolder = System.Environment.SpecialFolder.MyComputer;
DialogResult result = this.folderBrowserDialog1.ShowDialog();
if (result == DialogResult.OK)
{
// the code here will be executed if the user selects a folder
string path = this.folderBrowserDialog1.SelectedPath;
}
}
How do I list them like in the image, should I write it to an ini file, or XML file, and then if so how do I list it in the box as shown.
I also need to detect the OS and have few default folders in the list.
Not quite sure what you want, but the image shows a list with a string and bool value. So you can use something like this:
public class DirOptions
{
string Path = string.Empty;
bool IncludeSubDirs = false;
}
Then you can store your data inside a List<>:
var list = new List<DirOptions>();
To detect OS:
Please see this question Get OS Version / Friendly Name in C#

Categories