Hi I want to set the Text property of a Textbox by code behind. At the moment I do using XAML:
<TextBox x:Name="txtFilter" Text="{Binding FiltroFunzioni, Mode=OneWayToSource}" Grid.Row="0" />
As test I did this:
Binding b = new Binding();
b.Mode = BindingMode.OneWayToSource;
b.Path = new PropertyPath("Text"); //??
b.Source = PageViewModel.FiltroFunzioni;
BindingOperations.SetBinding(txtFilter, TextBlock.TextProperty, b);
The variable "FiltroFunzioni" is a string defined as property:
private string _filtroFunzioni = "";
public string FiltroFunzioni
{
get { return _filtroFunzioni; }
set
{
_filtroFunzioni = value;
RaisePropertyChanged("FiltroFunzioni");
_functionsView.Refresh();
}
}
Basically I dunno what kind of value should I set as PropertyPath. Any ideas?
You don't need the PropertyPath here. If you just remove it, your binding should work.
That being said, you should bind in XAML wherever possible.
If your issue is that changes to FiltroFunzioni don't update your textbox, that's because your binding is specifically declared as OneWayToSource: that means that changing the UI changes the source, but changing the source doesn't change the UI. If that isn't what you want, set the Mode to something else, like "TwoWay" - then changes to the source change the UI, AND changes to the UI change the source.
EDIT:
If you really want to bind from your ViewModel instead of just using XAML, TwoWay binding requires utilizing the Path for some reason, when binding through C#. Either of the following solutions work:
b.Source = FiltroFunzioni;
b.Path = new PropertyPath(".");
b.Source = this;
b.Path = new PropertyPath("FiltroFunzioni");
Note that with TwoWay binding you have to either initialize your FiltroFunzioni by setting the TextBox.Text property in your XAML, or setting FiltroFunzioni after the binding was initialized. Otherwise, WPF will immediately override it from the (by default empty) Text in your TextBox.
Related
I'm able to bind the property from entity to a listview content page element as below,
highlightGrid.SetBinding(IsVisibleProperty, "IsPaymentPlanEnding");
But I want to how do I bind this "IsPaymentPlanEnding" property value to a variable. Trying with the below code, but it is throwing a compilation error.
bool IsPaymentPlanEnding = BindingContext.GetBindingValue("IsPaymentPlanEnding");
Please let me know how do I bind the entity property value to variable.
You can store your binding in a variable like this:
BindingBase paymentPlanEndingBinding = new Binding("IsPaymentPlanEnding");
Then reference it when doing the actual binding:
highlightGrid.SetBinding(IsVisibleProperty, paymentPlanEndingBinding);
I wrote a simple unit test for that:
[Test]
public void BindingBase_test()
{
MockForms.Init();
BindingBase binding = new Binding("Value");
var pickerItem = new PickerSearchItem {Value = "the_value"};
var label = new Label {BindingContext = pickerItem};
label.SetBinding(Label.TextProperty, binding);
label.Text.ShouldBe("the_value");
}
Your BindingContext needs to Implement INotifyPropertyChanged.
And the BindingContext should hold a property (of type bool) called IsPaymentPlanEnding.
Then you can just leave the line as it is:
highlightGrid.SetBinding(IsVisibleProperty, "IsPaymentPlanEnding");
Learn about Bindings
I have the following code that creates a binding in code-behind. However, it does not seem to work (when the text in PageMarginTextBox is changed, nothing happens, and when the app is loaded, the Padding of newPage is not set to the text of PageMarginTextBox). To make matters worse, no Exceptions are thrown at all. All elements have been defined earlier on.
Binding pageMarginBinding = new Binding
{
Source = PageMarginTextBox,
Path = new PropertyPath("Text"),
};
newPage.SetBinding(ContentControl.PaddingProperty, pageMarginBinding);
//PageMarginTextBox.Text determines the Padding of newPage
How can I fix this? Any solutions would be appreciated. Thanks!
You are trying to Bind PaddingProperty to text. Padding property is of type Thickness and Text property is String.
I am not sure whether you want to bind padding / text, just giving you an idea if you want to bind the Padding.
Binding pageMarginBinding = new Binding
{
Source = PageMarginTextBox,
Path = new PropertyPath("Padding"),
};
newPage.SetBinding(ContentControl.PaddingProperty, pageMarginBinding);
Your problem is because you are trying to assign a string to a Thickness. In XAML the compiler internally translates the string "0,0,2,2" to Thickness object. But in code behind you have to write the code for the conversion yourself.
ThicknessConverter myThicknessConverter = new ThicknessConverter();
PageThickness= (Thickness)myThicknessConverter.ConvertFromString(PageMarginTextBox.Text);
Then you have to bind this to your control. Again this is only half the solution. You need to wire this up with the Binding.
private Thickness _pageThickness;
public Thickness PageThickness
{
get
{
return _pageThickness;
}
set
{
_pageThickness = value;
NotifyPropertyChanged("PageThickness");
}
Then you probably can bind it in XAML
I have an attached property I defined.
namespace Controls
{
public class StateManager : DependencyObject
{
public static string GetVisualState(DependencyObject obj)
{
return (string)obj.GetValue(VisualStateProperty);
}
public static void SetVisualState(DependencyObject obj, string value)
{
obj.SetValue(VisualStateProperty, value);
}
// Using a DependencyProperty as the backing store for VisualStateProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty VisualStateProperty =
DependencyProperty.RegisterAttached("VisualState", typeof(string), typeof(StateManager),
new PropertyMetadata(null,
(s, e) => {
var stateName = (string)e.NewValue;
var ctrl = s as Control;
if (ctrl == null) throw new InvalidCastException("You can only attach VisualState properties to Controls");
if (!string.IsNullOrEmpty(stateName))
VisualStateManager.GoToState(ctrl, stateName, true);
}));
}
}
I can bind to this property in XAML Like this:
<controls:TitleStrip
controls:StateManager.VisualState=
"{Binding (controls:StateManager.VisualState), ElementName=pageRoot}"
Grid.Column="1"/>
Now, I need to create a binding dynamically in code behind to the same property, so I tried this:
var pp = new PropertyPath("(controls:StateManager.VisualState)");
var binding = new Binding() { Path= pp, Source=this };
BindingOperations.SetBinding(ct, StateManager.VisualStateProperty, binding);
Unfortunately, setting the Path property of the binding, throws an ArgumentException stating: "Value does not fall within the expected range."
If instead, I substitute "(Grid.Row)" for my property, no exception is thrown.
Further investigation on windows 10 shows that this appears to work in C# codebehind, if trying to bind to the attached property Controls.StateManager.VisualState onto the Attached Property of the same name on the control ct:
string bindingxaml =
#"<ResourceDictionary
xmlns:controls=""using:Controls""
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
>
<Binding x:Key=""binding"" Path=""(controls:StateManager.VisualState)"" />
</ResourceDictionary>";
ResourceDictionary dict = XamlReader.Load(bindingxaml) as ResourceDictionary;
Binding binding = dict["binding"] as Binding;
binding.Source = this;
BindingOperations.SetBinding(ct, StateManager.VisualStateProperty, binding);
Strangely, this throws exceptions if you don't enclose it in a ResourceDictionary, and try to create the Binding object as the only child.
To debug this, I thought maybe my syntax was wrong for the namespace, so in my xaml resources section, I added this:
<Binding x:Key="yuck" Path="(controls:StateManager.VisualState)" ElementName="pageRoot" />
When I examined the Path of the property path, it was exactly as I specified it.
As a workaround, I'm currently getting the binding like this from code behind:
BindingOperations.SetBinding(ct, StateManager.VisualStateProperty,
Resources["yuck"] as Binding);
This appears to be working, however why can't I create the object from code behind?
Update
This worked on Windows 8 apps, but now gives errors on UWP.
To get it to work on UWP, I had to databind to the Tag of my ParentGrid.
<Grid x:Name="ParentGrid" Tag="{Binding ElementName=pageRoot, Path=(controls:StateManager.VisualState)}">
Then I can create a Binding to the Tag, like this:
var pp3 = new PropertyPath("Tag");
barf = new Binding() { Path = pp3, Source = ParentGrid };
I have a ScatterViewItem, which contains a UserControl. I'm trying to bind the MinWidth of the ScatterViewItem to the UserControl.
ScatterViewItem svi = new ScatterViewItem();
MyUserControl myUserControl = new MyUserControl();
//Make UC follow SVI's size. This code works.
myUserControl.SetBinding(UserControl.WidthProperty, svi.Width.ToString());
myUserControl.SetBinding(UserControl.HeightProperty, svi.Height.ToString());
//Make SVI follow UC's Min size. This doesn't work.
svi.SetBinding(ScatterViewItem.MinWidthProperty, myUserControl.MinWidth.ToString());
svi.SetBinding(ScatterViewItem.MinHeightProperty, myUserControl.MinHeight.ToString());
svi.Content = myUserControl;
myScatterView.Items.Add(svi);
Why is it that binding UC to SVI works and not the other way? How do I bind the MinWidth of the SVI to the UC then?
The SetBinding method has 2 overloads (source: http://msdn.microsoft.com/en-us/library/ms598270(v=vs.110).aspx):
SetBinding(DependencyProperty, String)
SetBinding(DependencyProperty, BindingBase)
What you are trying to achieve by using the ToString() is not working, since the ToString() converts the value of the (Min)Width and (Min)Height properties to a string (for example 500.0 => "500.0"). The SetBinding overload that accepts a string as second parameter expects that string to be a property name or a path to the property.
What you probably want, is "MinWidth", "Width", "MinHeight" or "Height":
myUserControl.SetBinding(UserControl.WidthProperty, "Width");
myUserControl.SetBinding(UserControl.HeightProperty, "Height");
svi.SetBinding(ScatterViewItem.MinWidthProperty, "MinWidth");
svi.SetBinding(ScatterViewItem.MinHeightProperty, "MinHeight");
Edit: this is the correct version, using the other overload, since the previous piece of code doesn't know where to find the specified properties.
Binding widthBinding = new Binding("Width");
widthBinding.Source = myUserControl;
svi.SetBinding(ScatterViewItem.MinWidthProperty, widthBinding);
Binding heightBinding = new Binding("Height");
heightBinding.Source = myUserControl;
svi.SetBinding(ScatterViewItem.MinHeightProperty, heightBinding);
To bind your ScatterViewItem's MinWidth to your usercontrol's MinWidth, you need to create a binding with the source set to the usercontrol and path set to "MinWidth". This binding is then assigned to the ScatterViewItem with SetBinding.
// Create Binding
Binding b = new Binding("MinWidth");
b.Source = myUserControl;
// Assign Binding to ScatterViewItem
svi.SetBinding(ScatterViewItem.MinWidthProperty, b);
Is it possible to attach datatriggers to a style at runtime? I've been through my (non-working) code a few times now and can't seem to find where I've gone wrong.
Here's the method I use to attach the style and trigger:
private void AttachVisibilityTrigger(Control ctrl)
{
Style stl = new System.Windows.Style();
DataTrigger dt = new DataTrigger();
PropertyInfo pi = _entity.GetType().GetProperty(this.SecondaryOptions[ctrl.Name]);
Type controlType = this.GetControlTypeForProperty(ref dt, pi); //gets the control type based on the property name and then sets the value for the DataTrigger for which I want the visibility to be hidden
Binding b = this.GetVisibilityBindingByControlType(controlType); //returns a new Binding with the appropriate Path set that corresponds to the bound property value (e.g IsChecked for CheckBoxes, Text for TextBoxes, SelectedValue for Comboboxes, etc)
b.ElementName = this.SecondaryOptions[ctrl.Name];
dt.Binding = b;
dt.Setters.Add(new Setter(Control.VisibilityProperty, System.Windows.Visibility.Hidden));
stl.Triggers.Add(dt);
ctrl.Style = stl;
}
I'm pretty sure the binding is just broken, i created similar styles in code and they work.
Especially this line looks quite suspicious:
b.ElementName = this.SecondaryOptions[ctrl.Name];
(If you want to bind to the control itself use RelativeSource instead.)
Have you checked the Output window of VisualStudio for binding errors?