This is a bit of a confusing scenario. Basically, I'm trying to set a button's color when I use setter for a private variable that I store its color in.
First off, I have a seperate window for customizing stuff. When I change the button color, I want to change every button in this window as well. I have it stored in a static variable in my main form class.
public static frm_custom customizer;
This is the setter for the variable in question.
private Color _buttonColor;
public Color buttonColor
{
get { return this._buttonColor; }
set
{
this.btn_input.BackColor = buttonColor;
this._buttonColor = buttonColor;
if (Application.OpenForms.OfType<frm_custom>().Count() == 1)
{
customizer.setButtonColor(buttonColor);
}
}
}
Strangely, it doesn't effect the color at all. Did I do something wrong?
Did I do something wrong?
Yes. Your setter is just fetching the existing property value:
this.btn_input.BackColor = buttonColor;
this._buttonColor = buttonColor;
You meant to use value, which is the implicit parameter name for the setter:
this.btn_input.BackColor = value;
this._buttonColor = value;
(Ditto for your if block, but it's hard to tell how that's meant to work as it's not valid C# at the moment.)
As a side note, I'd strongly urge you to start following .NET naming conventions, which include capital letters for properties - so ButtonColor rather than buttonColor.
Related
I'm a beginner, and I think that the solution is very simple, but I can't find it all over the Internet.
I'm looking for a way of setting the back color of forms and controls to a certain color variable so if I change its value to green for exapmple, every control that its back color set to mainColor will turn green and that the changes will show up in the designer.
public class MainForm:Form
{
public static Color mainColor=[some color];
public static Color secColor=[some color];
public Main()
{
InitializeComponent();
BackColor=mainColor;
control1.BackColor=secColor;
control2.BackColor=secColor;
control3.BackColor=secColor;
}
}
Like that by changing mainColor and secColor. The controls are changed, but it wont show up in the designer. What is the right way of doing it?
Use the Colors class.
public static Color redColor = Colors.Red;
public static Color greenColor = Colors.Green;
public static Color blueColor = Colors.Blue;
public static Color whiteColor = Colors.White;
Here is a pallete of the available colors:
If you want to create a new color, use Color.FromArgb();
Check out this answer for more information on new colors.
Yes, that is called DataBinding, and it's done partly with the Designer and partly with code.
Instead of declaring
public static Color mainColor=[some color];
declare it as a property:
public Color MyColor
{
get
{
return myColor;
}
set
{
myColor = value;
}
}
In your main form, edit each of the controls that you want to be influenced by this variable to bind their color property to it. I'll use a Panel as the sample control, so add some Panel objects to your form. Then in each Panel object, in the Properties panel, click the + next to DataBindings, then click in the empty box next to (Advanced). Click the ellipsis (...) and select the BackColor property. Then, under the Binding dropdown, select Add Project Data Source. Select Object in the next dialog and navigate to your form, and select that. A list of properties will then appear in the Formatting and Advanced Binding dialog box and you can select your property MyColor.
Note that once you have created this data source for the first one, you won't need to recreate it for each Panel - just reference the one you created already.
You can then change the BackColor of any of the controls you did this databinding on by changing the value of the MyColor property in your program. They will all change together.
You will probably also need to arrange that property to broadcast the message that it has changed, so add this line to the set() method.
form1BindingSource.ResetBindings(false);
so that the set method looks like this.
set
{
myColor = value;
form1BindingSource.ResetBindings(false);
}
That tells the binding source object to notify all subscribers to update themselves, and it will happen automatically every time the MyColor property is changed.
I see here lot of similar question, but I still not find answer that help me in situation.
I have two frame(lets say FrameChild), one is "in" another(practically FrameChild is in this frame, lets say FrameMain).
When I insert all parameters in FrameChild and tap on button witch is on bottom of FrameMain I call method that return string...
Now when i get string i need to change textbox text in FrameChild
I have tray many way.
First idea was something like:
FrameChild frm = new FrameChild;
frm.textbox.text = "somestring";
But nothing happen.
Than i thing use some property.
in FrameChield:
public string setTicNo
{
set
{
textBox.Text = value;
}
}
in FrameMain:
FrameChild frm = new FrameChild;
frm.setTicNo = "somestring";
When i debbuging I get value, but textbox still is empty...
On the end I try to bind textbox text on setTicNo;
public string setTicNo
{
get
{
return setTicNo;
}
set
{
setTicNo = value;
}
}
Xaml:
Text = {Binding setTicNo, Mode=TwoWay,UpdateSourceTrigger=Explicit}
(here i try use more bindings, but every time i get infinite loop.
Please help , I not have more ideas..
Thanx
Did you try building a single view model and bind it to both frames, if it was passed by ref which is the default it will change the value once you do.
A side note implement a INOTIFYPROPERTYCGANGED in the View model
I am working on a WPF application and i have a textbox bound (bidirectionally) to a property in my view model.
I am trying to prevent a user from typing more than 100 characters into this textbox (this is the max the database will store) so i have written this.
public abstract class AppBaseViewModel : ViewModelBase
{
private String _text;
public String Text
{
get { return _text; }
set
{
_text = CheckTextLength(value, _text);
OnPropertyChanged("Text");
}
}
private string CheckTextLength(string value, string text)
{
if (value.Length < 100)
{
return value;
}
else
{
return text;
}
}
}
All this code seems to do is save the first 100 characters to the field but it still allows the user to carry on typing past 100 characters... i would guess it is because the field value isn't being passed back to the textbox.
I don't understand why this doesn't work as i did something similar using MVVM Light's RaisePropertyChange() in a different application.
It is worth noting that i am unable to access the designer for the textbox so cannot set the .Net textbox property for max length.
Edit: Just for clarification i cannot view or edit the xaml as some are suggesting as i do not have access to the XAML file (i know, it's stupid). All the bindings we use are two way by default
Have you tried with TextBox.MaxLength ?
<TextBox MaxLength="100"/>
Gets or sets the maximum number of characters that can be manually entered into the text box.
If no access to the XAML, eventually get access to the XAML instead of parsing and verifying lengths of arrays and use substrings here and there. At least that's what i would do for this simple issue or talk to the designer to add that small piece of code.
Update 1
public static T GetChildOfType<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
Go and get that child and set its MaxLength. This is just a slight modification on the View so it will not affect the MVVM pattern.
OK. I'm not at all sure that I'm proud of this, but am presenting it as an alternative.
You can change the UpdateSourceTrigger of the TextBox's Text property by applying a universal Style to all of the TextBoxes. This is only going to be practical in pretty weird arrangements, but the question is a little unusual in itself.
XAML codebehind:
//I'm using MVVM Light here - you need to be able to find an instance
//of your AppBaseViewModel somehow.
private ViewModelLocator _locator;
//View codebehind constructor, may need to change names as appropriate
public AppBaseView()
{
InitializeComponent();
//MVVM Light again
_locator = new ViewModelLocator();
//Create the binding
Binding binding = new Binding();
//Source = The instance of your ViewModel
binding.Source = _locator.AppBaseViewModel ;
binding.Path = new PropertyPath("Text");
binding.Mode = BindingMode.TwoWay;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
//Create a Style with no Key - this will apply to *all* TextBoxes
//without their own explicit Style set.
Style style = new Style(typeof(TextBox));
style.Setters.Add(new Setter(TextBox.TextProperty, binding));
//Add the Style to the XAML's Resources:
Resources.Add(typeof(TextBox), style);
}
The view won't listen to the PropertyChanged notification if it's currently trying to change the property itself.
The only thing that comes to mind is launching an extra delayed PropertyChanged notification when you detect the constraint is not met...
private string CheckTextLength(string value, string text)
{
if (value.Length < 100)
{
return value;
}
else
{
MyDispatcher.BeginInvoke(new Action(() =>
OnPropertyChanged("Text")),
DispatcherPriority.Loaded);
return text;
}
}
Can't try the code, so sorry if it doesn't build righ away. MyDispatcher could be your Application.Current.Dispatcher, for instance.
The xaml view /the binding is only updated when the textbox has lost focus. if the text entered is <100 then the value is set otherwise _text is set. this means that initially _text has no value so null will be set upon the if statement being false. i also suggest yo use RaisePropertyChanged(); and when used within the property itself no parameter is needed.
When coding in Visual Basic, I'm able to define triggers to variables like: Whenever the value of the variable is changed, this triggers a function, which in turn changes the value of another variable. I wonder if there is a way to do the same in C#; that is, I want to define a trigger to a variable, fired every time when the value of that variable is changed.
Below code is how I do it in VB. When running this App, whenever a new user logs in, the App assigns the username like ActiveUserName = "SomeUserName", and this in turn automatically updates the FormMain.StatusLabelUserName.Text in the form. So, is there a way to achieve this trigger in C#?
Public Property ActiveUserName() As String
Get
ActiveUserName = FormMain.StatusLabelUserName.Text
End Get
Set(ByVal Value As String)
FormMain.StatusLabelUserName.Text = Value
End Set
End Property
I believe you're looking for Properties
private int localMember;
public int publicProperty
{
get
{
return localMember;
}
set
{
localMember = value;
//Do whatever you want here.
}
}
The "get" block is run any time you access the value. The "set" block is run any time you assign a value.
This is handled by raising events. This post describes how to do it well.
This is a simple property. Here's the C# syntax:
public string ActiveUserName
{
get { return FormMain.StatusLabelUserName.Text; }
set { FormMain.StatusLabelUserName.Text = value; }
}
Properties can work the same in C#
public string ActiveUserName
{
get{ return FormMain.StatusLabelUserName.Text;}
set{FormMain.StatusLabelUserName.Text = value; /*do more stuff here; */}
}
This can get rather messy and somewhat rigid however. You may consider using events to accomplish the same thing.
Use INotifyPropertyChanged event.
Properties and the set brackets.
INotifyPropertyChanged could be implemented for WPF databindings for exemple.
Using Infragistics UltraGrid in WinForms in C#:
I am conditionally changing the color of the ForeColor of some GroupByRows on a grid. When the user clicks the row, the color changes back to the active/selected/hot tracked/whatever color until they click on something else. I'd like the text color of the rows that I have conditionally colored to never change. Here's how I'm setting the color:
Row.Appearance.ForeColor = System.Drawing.Color.Orange;
Any idea how to make it stick even when the row is clicked?
Thanks!
This can be done with a draw filter to set the fore color of the description since this would apply at all times.
A simple example is the following draw filter which will make all group by rows that have an integer value that is even orange:
public class GroupByRowDrawFilter:IUIElementDrawFilter
{
public bool DrawElement(DrawPhase drawPhase, ref UIElementDrawParams drawParams)
{
GroupByRowDescriptionUIElement element = (GroupByRowDescriptionUIElement)drawParams.Element;
if (element.GroupByRow.Value is int)
{
int value = (int)element.GroupByRow.Value;
if (value % 2 == 0)
{
drawParams.AppearanceData.ForeColor = Color.Orange;
}
}
return false;
}
public DrawPhase GetPhasesToFilter(ref UIElementDrawParams drawParams)
{
if (drawParams.Element is GroupByRowDescriptionUIElement)
return DrawPhase.BeforeDrawElement;
return DrawPhase.None;
}
}
To apply the draw filter use the following line of code:
this.ultraGrid1.DrawFilter = new GroupByRowDrawFilter();
Note that this approach requires that the condition be in the draw filter. If this doesn't work for you, you could modify your logic where you are currently setting the ForeColor to set the Tag property of the GroupByRow instead and then check the Tag property in the draw filter to determine if you need to apply your logic.
I think you should also change the
grd.DisplayLayout.Override.SelectedRowAppearance.ForeColor = System.Drawning.Color.Orange;
or better
grd.DisplayLayout.Override.GroupByRowAppearance.ForeColor = System.Drawning.Color.Orange;
sorry, but I'm away from a PC where I can test.
Usually these properties could be changed effectively in the InitializeLayout event where you get the Layout object inside the event arguments.
e.Layout.Override.GroupByRowAppearance.ForeColor = Color.Orange;
EDIT: At the moment the only solution that I have found is the following
private void grd_BeforeRowActivate(object sender, RowEventArgs e)
{
// You need to add the additional logic required by you to
// determine which rows need to have the forecolo changed...
if (e.Row.IsGroupByRow == true)
grd.DisplayLayout.Override.ActiveRowAppearance.ForeColor = Color.Orange;
else
grd.DisplayLayout.Override.ResetActiveRowAppearance();
}
Infragistics says:
the "Ability to have active and selected conditional appearances for the GroupByRows" has been determined to be a new product idea