How set a variable the Properties.Settings.Default? - c#

I have two Properties files that store colors.
Properties.Green.Theme
Properties.PurpleTheme
The names of the parameters in the files are completely the same. I want to implement a theme change by switching between these two files. The simplest thing, in theory, is to assign a variable a value with a visibility level for the entire class. For example, var theme = Properties.GreenTheme.Default. And then use this variable in the methods. because the names are the same everywhere. Sample code in what form I want to do it:
public partial class FrmMain : Form{
TypeVar theme = null;
public FrmMain()
{
InitializeComponent();
if (i = 1)
{
theme = Properties.GreenTheme.Default;
}
if (i = 3)
{
theme = Properties.PurpleTheme.Default;
}
SetBottonColor();
SetPanelColor();
}
private void SetBottonColor()
{
btn.BackColor = theme.button_color;
btn2.BackColor = theme.button_color;
btn3.BackColor = theme.button_color;
}
private void SetPanelColor()
{
panel.BackColor = theme.panel_color;
panel2.BackColor = theme.panel_color;
}
}
that is, in order not to prescribe if in each method, I want to create a variable at the class level and change it when loading the form. And since the names of the parameters in the files are the same, the colors would be taken from the desired file. Locally I can easily declare a variable
var theme = Properties.PurpleTheme.Default;
But I need it at the class level because there are a lot of such methods. object as var unfortunately does not work...
p.s. Sorry for my English

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}}"/>

Access data in datagridview from a class

I've read a lot of topics on this issue but I'm not finding an answer. I'm fairly new to this so please bear with me.
I'm trying to pass values from datagridview to a list. And then in a new class I want to make som methods accessing that list. Trouble is that when I pass the datagridview it returns it without content and values which means I can't do anything with it.
The code under ////TESTING//// works like I want. I create an instance of the specified list and it's counting the amount of rows properly, see screenshot.
public List<vertEl> getVertList = new List<vertEl>();
//Opens the file dialog and assigns file path to Textbox
OpenFileDialog browseButton = new OpenFileDialog();
private void browse_Click(object sender, EventArgs e)
{
browseButton.Filter = "Excel Files |*.xlsx;*.xls;*.xlsm;*.csv";
if (browseButton.ShowDialog() == DialogResult.OK)
{
//SOME CODE TO GET DATA FROM EXCEL AND SOME METHODS TO CALCULATE
//VALUES TO PASS TO THE TAB VERTIKALELEMENTER TAB IN MY DATAGRIDVIEW
//VERTIKALELEMENTER IS vertElementerDgv IN MY CODE
////TESTING////
GetVertElementasList TEST = new GetVertElementasList();
getVertList = TEST.vertList(vertElementerDgv);
MessageBox.Show(getVertList.Count.ToString());
}
else return;
}
I now want to do this in a seperate class and call a method from that class to do the same but when I try that with code underneath I do not get the same count as when I have the code in form1 (public partial class BridgeGeometry). It return count of 0. The method foo() is assigned to the button 1 in the form.
class GetKoord
{
public GetVertElementasList getList = new GetVertElementasList();
BridgGeometry obj = new BridgGeometry();
public void foo()
{
var TEST = getList.vertList(obj.vertElementerDgv);
//var TEST = obj.getVertList;
MessageBox.Show(TEST.Count.ToString());
}
}
I also tried to get the values directly from the datagridview but there's nothing in it when I access it from a class which is not the form1/BridgeGeometry class.
Form - screenshot
You could run a loop and store the information with selected rows into a public var with something like this:
string itemOne = dataGridView1.SelectedRows[0].Cells[1].Value + string.Empty;
string itemTwo= dataGridView1.SelectedRows[0].Cells[2].Value + string.Empty;
string itemThree = dgMasterGridBun.SelectedRows[0].Cells[3].Value + string.Empty;
Variables
public var varItemOne = itemOne;
public var varItemTwo = itemTwo;
public var varItemThree = itemThree;
Based on the link I managed to get this working. Probably not the best solution, but a working one. I tried to wrap my head around databinding, listbinding etc. but since the class with the input values are a messy one I gave that up for now. The datagriview input values are a little from lists and some from other datagridview.
MSDN-forum: Accessing Form1 controls from a different class
Explanations are given in the link so I'll just provide how I did it in my program.
If my GetKoord class are like this:
public class GetKoord
{
private BridgGeometry bridgeGeometry;
public GetKoord(BridgGeometry form1)
{
bridgeGeometry = form1;
}
public List<vertElementerParam> getListvertElementer(List<vertElementerParam> theList)
{
//var vertElementerDgv = bridgeGeometry.vertElementerDgv;
GetVertElementasList getVertElementasList = new GetVertElementasList();
List<vertElementerParam> MyDgvListList = new List<vertElementerParam>();
MyDgvListList = getVertElementasList.vertList(bridgeGeometry.vertElementerDgv);
//MessageBox.Show(MyDgvListList.Count.ToString());
theList = MyDgvListList;
return theList;
}
}
then I can get the list in Button1_Click like this, check the screenshot in the first post:
public List<vertElementerParam> getVertList = new List<vertElementerParam>();
private void button1_Click(object sender, EventArgs e)
{
GetKoord getKoord = new GetKoord(this);
List<vertElementerParam> testList = new List<vertElementerParam>();
testList = getKoord.getListvertElementer(getVertList);
MessageBox.Show(testList.Count.ToString());
}

Reset part of application settings

So, I have Form called Preferences with TabControl in it. This TabControl contains several TabPages(General, Advanced, Misc, ...) with few comboboxes, checkboxes and labels. Each of this control inside TabPage is assigned Application Settings Property Binding (aka they show saved user settings, user can change them etc...).
I know that there is a method to reset all settings (Properties.Settings.Default.Reset();), but is there a way how to reset only settings inside one TabPage?
My solution is to iterate thru controls in TabPage, check if it is combobox, label etc and then reset it´s value to default, but is there a "oneliner" solution to this ?
Use the following solution to get the original value of a single setting:
(The example assumes you want to get the ORIGINAL value of a setting named 'Username')
var defaultUsername = Properties.Settings.Default.GetType()
.GetProperty(nameof(Properties.Settings.Default.Username))
.GetCustomAttribute<System.Configuration.DefaultSettingValueAttribute>()
.Value;
Important - this solution will always return a string value. make sure to parse it properly, or use this extension method I wrote:
public static T GetDefaultValue<T>(this ApplicationSettingsBase settings, string settingKey)
{
return (T)Convert.ChangeType(settings.GetType()
.GetProperty(settingsKey)
.GetCustomAttribute<DefaultSettingValueAttribute>()
.Value, typeof(T));
}
Usage:
var defaultNumber = Properties.Settings.Default.GetDefaultValue<int>(nameof(Properties.Settings.Default.Number));
The ApplicationSettings doesn't have built-in support to reset just some properties. But to solve the problem, you can use either of these options:
Create a method which resets all bound controls of a TabPage
Using Multiple Settings Files with Designer Support
Option 1 - Create a method which resets all bound controls of a TabPage
You can create a method which look at controls of the tab page and check if it's bound to application settings, find the property in settings and reset its value to the default value. Then you can reset settings of a TebPage width one line of code: ResetSettings(tabPage1);.
Here is the method:
private void ResetSettings(TabPage tabPage)
{
foreach (Control c in tabPage.Controls)
{
foreach (Binding b in c.DataBindings)
{
if (b.DataSource is ApplicationSettingsBase)
{
var settings = (ApplicationSettingsBase)b.DataSource;
var key = b.BindingMemberInfo.BindingField;
var property = settings.Properties[key];
var defaultValue = property.DefaultValue;
var type = property.PropertyType;
var value = TypeDescriptor.GetConverter(type).ConvertFrom(defaultValue);
settings[key] = value;
//You can also save settings
settings.Save();
}
}
}
}
Option 2 - Using Multiple Settings Files with Designer Support
If the reason of using a single settings file is because of designer support, you should know you can have designer support also with multiple settings files. Then you can use different settings files and reset each settings group separately. You can simply encapsulate them in a single class using such code:
public static class MySettings
{
public static Sample.General General
{
get { return Sample.General.Default; }
}
public static Sample.Advanced Advanced
{
get { return Sample.Advanced.Default; }
}
public static void ResetAll()
{
General.Reset();
Advanced.Reset();
}
public static void SaveAll()
{
General.Save();
Advanced.Save();
}
}
To reset a setting group it's enough to call MySettings.General.Reset();
To reset all settings, you can call MySettings.ResetAll();
Note for design-time support
To have designer support for binding properties to settings, create multiple settings files in root of your project. Don't put settings files in folders. The setting picker, only shows Settings.settings file which is in Properties folder and those files which are in root of project. This way you can see different settings files and settings properties in a tree-view like this:
TabPage page = aTabControl.SelectedTab;
var controls = page.Controls;
foreach (var control in controls)
{
//do stuff
}
Try this:
private void button2_Click(object sender, EventArgs e)
{
TabPage page = tabControl1.SelectedTab;
var controls = page.Controls;
foreach (var control in controls)
{
if(control is TextBox)
{
//do stuff
}
if(control is ComboBox )
{
ComboBox comboBox = (ComboBox)control;
if (comboBox.Items.Count > 0)
comboBox.SelectedIndex = 0;
comboBox.Text = string.Empty;
}
}
}

How to read a stack.peek in order to put it in an if statement C#

I am trying to create a menu system and i am storing the menus in stacks once they have already been visited. Im trying to use Stack.Peek() to basically say: if menuName = menuStack.Peek, then continue.
menus have a drawRectangle, sprite, and Menuname enumeration associated with them, and all menus are child classes of the Menu class.
public static void GoToMenu(MenuName menuName)
{
Stack<Menu> menuStack = new Stack<Menu>();
Stack<Menu> tempStack = new Stack<Menu>();
if(menuStack.Peek() = MainMenu){
}
}
More or less, if menuStack.Peek returns a mainMenu object. How do i check that?
i just really dont know how to read menuStack.Peek(). I dont know how to apply it to an if statement to check if it equals a mainmenu object, a pausemenu object or whatever.
public static void GoToMenu(MenuName menuName)
{
Stack<Menu> menuStack = new Stack<Menu>();
Stack<Menu> tempStack = new Stack<Menu>();
if(menuStack.Peek().Name == menuName){
menuStack.Pop();
}
}
that is what i needed

Windows Forms is getting too large

Im making a program with many many pages... and in my design, the buttons will eventually get stacked up, so its getting harder and harder to work the more there are.
This question is a clone of this topic.
However, i didn't really get the answer since they were talking about xaml and wpf.
I've also tried to make multiple windows forms, hide and show them to split it up.
But when i hide and show a wndow, its very very easily to see the GUI fading in and out which looks ugly.
I want an instant hide/show function so it looks like its just 1 program with 1 window and now switching.
So what are the tecniques to make a big windowsforms program more managable?
You may create a couple of UserControls, organize and separate your logic on them. Then you may use String Array to store your control names and iterate througth items to display apropriate view. The form may have Panel as container and Dock Style defined as Fill. The simplefied code will look like:
public class MyContainer:Control
{
public MyContainer(string szControlName, UserControl nControl)
{
UserControlName = szControlName; MyControl = nControl;
}
public string UserControlName { get; set; }
public UserControl MyControl { get; set; }
}
In main form:
public List<MyContainer> MyNavigationArray;
public void InitArray()
{
MyNavigationArray = new List<MyContainer>(MyFormPageCount);
for (int i = 0; i < MyFormPageCount; i++)
{
MyNavigationArray.Add(new MyContainer(TheNameOfUserControl, new PredefinedUserControl()));
}
}
private void NextButton_click(object sender, EventArgs e)
{
MyContainer mYcn = this.panel1.Controls[0] as MyContainer;
int nCurPos = MyNavigationArray.IndexOf(mYcn);
if (nCurPos < MyNavigationArray.Count)
{
panel1.Controls.Clear();
MyContainer c = MyNavigationArray[nCurPos + 1];
panel1.Controls.Add(c);
c.Dock = DockStyle.Fill;
}
}
All information stored inside user controls will be in your array and can be used later.
Hope this helped.

Categories