WPF Binding issue with updating values - c#

I have a .xaml file and a .cs file that share value with Binding.
To make it simples, I have 1 button and 1 textbox. I want to button to be disabled when the textbox's text has no character.
Here is the two codes of the xaml for binding:
<TextBox Name="txtSend" Text="{Binding Path=CurrentText,UpdateSourceTrigger=PropertyChanged}"></TextBox>
<Button IsEnabled="{Binding Path=IsTextValid}" Name="btnSend">Send</Button>
The two properties in the .cs file look like that:
public string CurrentText
{
get
{
return this.currentText;
}
set
{
this.currentText = value;
this.PropertyChange("CurrentText");
this.PropertyChange("IsTextValid");
}
}
public bool IsTextValid
{
get
{
return this.CurrentText.Length > 0;
}
}
The this.PropertyChanged is simply a method that call PropertyChanged from INotifyPropertyChanged.
The problem is that I have to call the this.PropertyChange("IsTextValid"); in the Setter of the CurrentText to be able to have the button state change.
Question 1) Is it the good way to do it... if the rules become more complexe I might require to call a lot of PropertyChanged...?
Question 2) My button is enable when the form load. How can I make it check the method from the start?

Question 1: This is correct. There is no problem doing that. However you could take a look at the validation using the IDataErrorInfo. (Google search for it, and you will find a lot of good examples)
Question 2: make sure your "currentText" string is initialized with string.empty. Because if you did not initialized it, it will be null, and the getter for IsTextValid will throw an exception, and WPF will fail to retrieve the value.
Or do it like that:
public bool IsTextValid
{
get
{
return ! string.IsNullOrEmpty( this.CurrentText );
}
}

Your way of doing it is correct. If you are a bit lazy (as I am), you should have a look on the NuGet package Fody.PropertyChanged.
Your code would simplify to
public string CurrentText { get; set; }
public bool IsTextValid { get { return this.CurrentText.Length > 0; } }
Fody.PropertyChanged does the rest for you. It automatically adds the needed instructions to notify that CurrentText changed, and it even detects that IsTextValid depends on CurrentText and notifies for it, too.

Related

Change Textbox text from another frame(container)

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

How to assign triggers to variables in C#?

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.

How do the internals of SelectedValuePath work (on combobox/listbox)?

I'm trying to solve another question of mine (here), and I'm stuck on the internals of changing the SelectedValuePath in code.
It seems that depending on what I'm changing from/to, different things will happen.
I've researched SO, debugged it, and even tried to find the offending code in the MS dll's using dotPeek, but for no avail so far.
If I'm changing from any type of property to a string property, it works ok.
Changing from string to int will throw an exception.
Changing from bool to int depends:
If the property was false, the selected index will change to 0, and the selected value will change to false (not an int, as it was supposed to be)
If the property was true, the selected index will change to -1, and the selected value will be null.
My assumption is that somewhere someone is trying to parse something, and depending on what happens, the results might or might not work.
Since SelectedValuePath receieves strings as input, and just sets the SelectedValue to whatever they are pointing at. I would expect that when changing this the SelectedItem will not change, and that the correct value will show. I did not expect to get this myriad of different results/exceptions/behaviors ...
The only thing That comes to mind is that the type of SelectedValue is set to whatever the property that SelectedValuePath points at, and then when it changes, it might encounter a wrong type...
As a workaround, setting the SelectedValuePath to null before setting it to a new property seems to work (avoiding any exceptions being thrown).
Edit:
I've updated the project with some more types, and you can find it here.
The offending bit is in a Try/Catch block, and extra information is shown whenever something weird happens.
question 1: The behavior that puzzles me is: Changing from string to any other type (once you have selected an item), will throw an exception, and the SelectedValue will not change anymore (setting it to the default will fix this problem).
Why is the System.FormatException: Input string was not in a correct format thrown, and what was being changed??
(I have expected that changing the SelectedValuePath willsimply "reset" the SelectedValue to the new object/type)
Also, changing the SelectedValuePath will reset the SelectedIndex in most cases to either -1, or 0.
Question 2: why is the index changed?
Not really an answer but too much for a comment
How are you using SelectedValuePath?
For example if you are binding it to a TextBlock Text then it expects string.
It does not make sense to me to change the type of a SelectedValuePath
For example:
<TextBlock Text="{Binding ElementName=employeeListBox,
Path=SelectedValue}"
Not going to download and debug your code but this simple example does not throw an exception for me
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
lbNoBinding.SelectedValuePath = "StrMix";
lbNoBinding.DisplayMemberPath = "StrMix";
}
public class MixedType
{
public string StrMix { get { return "strMix"; } }
public bool BoolMix { get { return true; } }
}
private List<MixedType> mixedTypes = new List<MixedType>() { new MixedType(), new MixedType() };
public List<MixedType> MixedTypes
{
get { return mixedTypes; }
}
private void btnClick(object sender, RoutedEventArgs e)
{
try
{
lbNoBinding.SelectedValuePath = "BoolMix";
lbNoBinding.DisplayMemberPath = "BoolMix";
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}

How to force a new property to be serialized in designer.cs

I added a new property to a component to uniquely identify every gridcontrol in my project, called GridIdentifier:
public class MyCustomGridControl : GridControl
{
private string gridIdentifier = "empty";
[Browsable(true)]
[DefaultValue("empty")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string GridIdentifier
{
get { return gridIdentifier; }
set { gridIdentifier = value; }
}
public MyCustomGridControl()
{
if (this.gridIdentifier == "empty")
this.gridIdentifier = Guid.NewGuid().ToString();
}
}
The problem is that for existing controls in my forms, the form only serializes the new property after I change something (read: anything) within the form. It might be the caption of the form, the size, etc.
But what I would like to see is that it detects that the form has changed when I open it, so I can save it and the new property gets serialized.
Does anyone have a clue why the new property doesn't get saved after opening the form and how to fix it? Any other ideas that help are of course also appreciated.
I would guess it is doing basic sanity checking (i.e. should anything have changed) - to prevent unexpected source code changes (I hate it when opening a file can cause side-effects - I'm looking at you, DBML!).
On a side note, to force serialization generally (I don't think it will apply due to the above):
public bool ShouldSerializeGridIdentifier() { return true; }
the bool ShouldSerialize*() and void Reset*() are a convention used by the framework.

Why does the VS2005 debugger not report "base." values properly? (was "Why is this if statement failing?")

I'm working on an existing class that is two steps derived from System.Windows.Forms.Combo box.
The class overrides the Text property thus:
public override string Text
{
get
{
return this.AccessibilityObject.Value;
}
set
{
if (base.Text != value)
{
base.Text = value;
}
}
}
The reason given for that "get" is this MS bug: http://support.microsoft.com/kb/814346
However, I'm more interested in the fact that the "if" doesn't work.
There are times where "base.Text != value" is true and yet pressing F10 steps straight to the closing } of the "set" and the Text property is not changed.
I've seen this both by just checking values in the debugger, and putting a conditional breakpoint on that only breaks when the "if" statement's predicate is true.
How on earth can "if" go wrong?
The class between this and ComboBox doesn't touch the Text property. The bug above shouldn't really be affecting anything - it says it's fixed in VS2005. Is the debugger showing different values than the program itself sees?
Update
I think I've found what is happening here.
The debugger is reporting value incorrectly (including evaluating conditional breakpoints incorrectly). To see this, try the following pair of classes:
class MyBase
{
virtual public string Text
{
get
{
return "BaseText";
}
}
}
class MyDerived : MyBase
{
public override string Text
{
get
{
string test = base.Text;
return "DerivedText";
}
}
}
Put a breakpoint on the last return statement, then run the code and access that property.
In my VS2005, hovering over base.Text gives the value "DerivedText", but the variable test has been correctly set to "BaseText".
So, new question: why does the debugger not handle base properly, and how can I get it to?
Use String.Compare for comparing strings. There are subtleties with strings. I cannot tell you why the if would fail, other than that your strings might not really be 'equal'
... and this just about wraps up my new question. Ah well.

Categories