Is it possible to bind to the ColumnSpan property? - c#

I am having trouble binding to the ColumnSpan property. After many hours of debugging, I am wondering if it is even possible.
public partial class MainPage : PhoneApplicationPage, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int myProperty;
public MainPage()
{
InitializeComponent();
Binding binding = new Binding("MyProperty");
binding.Source = this;
btn0.SetBinding(Grid.ColumnSpanProperty, binding);
}
public int MyProperty
{
get
{
return myProperty;
}
set
{
myProperty = value;
OnPropertyChanged("MyProperty");
}
}
protected virtual void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
Is it possible to bind to Grid.Column but not Grid.ColumnSpan? If it's possible with ColumnSpan, what am I doing wrong?

Thx a lot, Martin, that was it. Compiling fails if property is Zero.
So sick, I lost a day because of this.

Related

WPF C# PropertyChanged always null

I have played around with this for a while and decided to see if someone can help, I have set in the constructor of StatusInfo the DataContext = this and didn't work. When I write a string to ScreenStatusBarText it does call the OnPropertyChanged method but every time the PropertyChanged value is null. I The status block I have at the bottom of the screen. I have a tab section above this stack panel that has many components that use bindings and work.
Screen Code
<StackPanel Margin="0,1047,0,0">
<Grid Name="StatusBarItemGrid">
<TextBlock Name="StatusBarText" Text="may the force be with you" VerticalAlignment="Center" HorizontalAlignment="Stretch" />
</Grid>
</StackPanel>
Data Model:
public partial class StatusInfo : INotifyPropertyChanged
{
private string screenStatusBarText;
public StatusInfo()
{
BindScreenStatusBarText();
screenStatusBarText = "Initialized";
}
public string ScreenStatusBarText
{
get { return screenStatusBarText; }
set
{
screenStatusBarText = value;
OnPropertyChanged("StatusBarText");
}
}
private void BindScreenStatusBarText()
{
Binding b = new Binding();
b.Source = screenStatusBarText;
b.Mode = BindingMode.OneWay;
b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
b.Path = new PropertyPath("StatusBarText");
MainWindow.mainWindow.StatusBarText.SetBinding(TextBlock.TextProperty, b);
MainWindow.mainWindow.StatusBarText.DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(
this, new PropertyChangedEventArgs(propName));
}
}
My main :
public partial class MainWindow : Window
{
public static StatusInfo status;
public MainWindow()
{
InitializeComponent();
SourceInitialized += MainWindow_SourceInitialized;
}
private void MainWindow_SourceInitialized(object sender, EventArgs e)
{
SetUpDisplay();
}
private void SetUpDisplay()
{
status = new StatusInfo();
}
}
Set the Binding in XAML instead of code behind:
<TextBlock Text="{Binding ScreenStatusBarText}" />
And use a view model like
public class StatusInfo : INotifyPropertyChanged
{
private string screenStatusBarText = "Initialized";
public string ScreenStatusBarText
{
get { return screenStatusBarText; }
set
{
screenStatusBarText = value;
OnPropertyChanged(nameof(ScreenStatusBarText));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(propertyName));
}
}
with an instance of the view model class assigned to the MainWindow's DataContext:
private readonly StatusInfo statusInfo = new StatusInfo();
public MainWindow()
{
InitializeComponent();
DataContext = statusInfo;
}
You may now access the view model class at any time later, e.g. in an event handler of an element of MainWindow:
statusInfo.ScreenStatusBarText = "Something";
I think your going to struggle doing your binding in code behind.
Having said that, with regards to why your PropertyChanged value is null. You've simply made a typo, as-is you're notifying subscribers that a property that doesn't exist has changed. One solution to avoid such typos is to use nameof.
public string ScreenStatusBarText
{
get { return screenStatusBarText; }
set
{
screenStatusBarText = value;
OnPropertyChanged(nameof(ScreenStatusBarText));
}
}
It occurred to me you may also have meant that your event was null. This simply means you don't have any subscribers. See Why is my "Event" always null?.
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) // I have a subscriber.
handler(this, new PropertyChangedEventArgs(propertyName));
}

Two Way binding not working when set via Code behind

I am creating dynamic control in code behind and setting it's visibility property binding to the property in the code behind. But when the property value is changed, it's not updating visibility of the control.
Binding:
Binding assetsVisibilityBinding = new Binding();
assetsVisibilityBinding.Source = this;
assetsVisibilityBinding.Path = new PropertyPath("IsLocalSearchEnabled");
assetsVisibilityBinding.Mode = BindingMode.TwoWay;
assetsVisibilityBinding.Converter = Resources["BooleanToVisibilityConverter"] as IValueConverter;
assetsStackPanel.SetBinding(StackPanel.VisibilityProperty, assetsVisibilityBinding);
Property(Using fody):
public bool IsLocalSearchEnabled { get; set; }
maybe your class which contains the property needs to implement the interface
INotifyPropertyChanged
Let's assume your class name be A
then snippet will be
class A : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public bool isLocalSearchEnabled = false;
public bool IsLocalSearchEnabled
{
get { return isLocalSearchEnabled ;}
set { isLocalSearchEnabled = value; this.OnPropertyChanged("IsLocalSearchEnabled");
}
}
What happens here when you implement INotifyPropertyChanged is the event PropertyChanged
is triggered when the value of isLocalSearchEnabled is set (regardless of old value and new value) and OnPropertyChanged is called with the name of Public property
It seems you have not implemented INotifyPropertyChanged interface, please see the detailed example INotifyPropertyChanged
Did you set the assetsStackPanel DataContext the binding need the source ,that you should set the DataContext ont only set the source.
If you set the property in this in xaml.cs that you should make it public.
Binding assetsVisibilityBinding = new Binding();
assetsVisibilityBinding.Source = this;
assetsVisibilityBinding.Path = new PropertyPath("IsLocalSearchEnabled");
assetsVisibilityBinding.Mode = BindingMode.TwoWay;
assetsVisibilityBinding.Converter = Resources["BooleanToVisibilityConverter"] as IValueConverter;
assetsStackPanel.DataContex=this;
assetsStackPanel.SetBinding(StackPanel.VisibilityProperty, assetsVisibilityBinding);
For I have not read frameWork ,I think you can try use property by INotifyPropertyChanged to know whether code is right.
And you can use BindingOperations.SetBinding
Try use resharper in xaml and write Visibility="{Binding RelativeSource={RelativeSource AncestorType=Window},Path=IsLocalSearchEnabled}",mode=TwoWay.If it can work that is mean the FrameWork can work.
Thanks. But as mentioned in the post I am actually using
Fody(github.com/Fody/PropertyChanged). Which automatically implements
that
I have checked the complied class, by using Fody PropertyChanged the property changed notification wasn't successfully implemented.
[ImplementPropertyChanged]
public sealed partial class MainPage : Page
{
public bool IsLocalSearchEnabled { get; set; }
public MainPage()
{
this.InitializeComponent();
SetBinding();
this.DataContext = this;
}
public void SetBinding()
{
Binding assetsVisibilityBinding = new Binding();
assetsVisibilityBinding.Source = this;
assetsVisibilityBinding.Path = new PropertyPath("IsLocalSearchEnabled");
assetsVisibilityBinding.Mode = BindingMode.TwoWay;
assetsVisibilityBinding.Converter = Resources["BooleanToVisibilityConverter"] as IValueConverter;
assetsStackPanel.SetBinding(StackPanel.VisibilityProperty, assetsVisibilityBinding);
}
}
I would suggest you reporting issue to Fody to fix it.
The standard way as follows:
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
bool isLocalSearchEnabled;
public bool IsLocalSearchEnabled
{
get { return isLocalSearchEnabled; }
set
{
if (value != isLocalSearchEnabled)
{
isLocalSearchEnabled = value;
OnPropertyChanged("IsLocalSearchEnabled");
}
}
}
public MainPage()
{
this.InitializeComponent();
SetBinding();
this.DataContext = this;
}
public void SetBinding()
{
Binding assetsVisibilityBinding = new Binding();
assetsVisibilityBinding.Source = this;
assetsVisibilityBinding.Path = new PropertyPath("IsLocalSearchEnabled");
assetsVisibilityBinding.Mode = BindingMode.TwoWay;
assetsVisibilityBinding.Converter = Resources["BooleanToVisibilityConverter"] as IValueConverter;
assetsStackPanel.SetBinding(StackPanel.VisibilityProperty, assetsVisibilityBinding);
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Or you can easily use a wrapper class: BindableBase

Calling OnPropertyChange("property_name") Sends Updates to All Bound Properties

So I have a class with 40 or so properties that are updated from communication with a micro controller. This class implements INotifyPropertyChanged.
Loose Example:
private int _Example;
public int Example
{
get
{
return _Example;
}
set
{
_Example = value;
OnPropertyChange("Example");
}
}
And the OnPropertyChange function:
protected void OnPropertyChange(string p_Property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(p_Property));
}
}
public event PropertyChangedEventHandler PropertyChanged;
Binding (many of these)
Second_Class_Control.DataBindings.Clear();
Second_Class_Control.DataBindings.Add("My_Property", FirstClass, "Example");
In the main form I've set up binds to display and react to these values. One of those happens to land on another property in a another class. I happened to place a breakpoint in the set function of this property, and noticed it was being called any time any property from the first class changed.
Is this the correct behavior? I don't notice any performance hits but I plan on having many instances of these classes running together and wasn't expecting this.
Thanks
Hmm.. I noticed that you have the your OnPropertyChange virtual. Why is this, are you making a override somewhere?
I usually creates it like this :
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
then for the usage :
public class MainWindowViewModel : ViewModelBase
{
private string name;
public string Name
{
get { return name; }
set { name = value; OnPropertyChanged("Name"); }
}
}

Data binding not working, What is wrong? Silverlight WP7

I'm new to Silverlight and i'm trying to use Databinding.
This looks simple but it's not working and I can't find why...
In my MainPage.xaml
<map:Map Name="bing_map" Height="578" Width="480"
ZoomLevel="{Binding ZoomLevel, Mode=TwoWay}"
Center="{Binding Center, Mode=TwoWay}"
CredentialsProvider="{StaticResource BingMapsKey}" />
As you can see, I'm attempting a binding on ZoomLevel and Center.
In my MainPage.xaml.cs
The class inherit from INotifyPropertyChanged
In the constructor:
ZoomLevel = 12.0;
Center = new GeoCoordinate(0, 0);
The properties:
private double _zoom_level;
private double ZoomLevel
{
get { return _zoom_level; }
set {
if (_zoom_level == value) return;
_zoom_level = value;
RaisePropertyChanged("ZoomLevel");}
}
private GeoCoordinate _center;
private GeoCoordinate Center
{
get { return _center; }
set {
if (_center == value) return;
_center = value;
RaisePropertyChanged("Center"); }
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
I'm I forgetting something?
I have stuck on this for 3 hours starting to be a while for a simple binding...
Thank you in advance for your help! :)
Try changing the properties to public:
private double _zoom_level;
public double ZoomLevel
{
get { return _zoom_level; }
set {
if (_zoom_level == value) return;
_zoom_level = value;
RaisePropertyChanged("ZoomLevel");}
}
private GeoCoordinate _center;
public GeoCoordinate Center
{
get { return _center; }
set {
if (_center == value) return;
_center = value;
RaisePropertyChanged("Center"); }
}
And also set the View DataContext: (as Ray mentioned in his answer)
public partial class MainPage
{
public MainPage()
{
this.DataContext = this;
}
}
It is highly recommended to use the MVVM pattern.
In addition to the properties needing to be public (as per MichaelS's answer), bindings reference the object that is set to the control's DataContext (or its parent's DataContext).
So typically you wouldn't have your Window implement INotifyPropertyChanged but you would create another class (normally called a ViewModel) that implements INotifyPropertyChanged and set that to the Window's DataContext.
e.g.
public class MainWindowViewModel : INotifyPropertyChanged
{
private GeoCoordinate _center;
public GeoCoordinate Center
{
get { return _center; }
set
{
if (_center == value) return;
_center = value;
RaisePropertyChanged("Center"); }
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Then in your MainPage.xaml.cs you could do something like this
public partial class MainPage
{
public MainPage(MainWindowViewModel vm)
{
this.DataContext = vm;
}
}
Of course, a quick fix for you might be to just set your DataContext for the page to be itself.
e.g.
public partial class MainPage
{
public MainPage()
{
this.DataContext = this;
}
}

Having ObservableCollection Trigger an update

So i have something along the lines of
private ObservableCollection<ViewModel> _internal;
public ObservableCollection<ViewModel> BoundInternal{get;set}; //this is Binded in the Itemssource like ItemSource={Binding BoundInternal}
Now In my code i do something like
BoundInternal=_internal, However the problem is the BoundInternal isn't trigger any collectionChanged event. I have to use the Add method. So I am wondering if there is a solution to this.
Here is what I suspect your code ought to look like like (although its not quite a match for what you currently doing):-
public class YourClassHoldingThisStuff : INotifyProperyChanged
{
private ObservableCollection<ViewModel> _internal;
public ObservableCollection<ViewModel> BoundInternal
{
get { return _internal; }
set
{
_internal = value;
NotifyPropertyChanged("BoundInternal");
};
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new ProperytChangedEventArgs(name));
}
}
In this case the _internal field becomes the source of the value of BoundInternal directly and you should only assign it via BoundInternal, (don't assign a value directly to _internal). When that occurs anything currently bound to it will be informed of the change.
If for some reason you really do need to maintain _internal as a separate reference from the backing field of BoundInternal then:-
public class YourClassHoldingThisStuff : INotifyProperyChanged
{
private ObservableCollection<ViewModel> _internal;
private ObservableCollection<ViewModel> _boundInternal;
public ObservableCollection<ViewModel> BoundInternal
{
get { return _boundInternal; }
set
{
_boundInternal = value;
NotifyPropertyChanged("BoundInternal");
};
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new ProperytChangedEventArgs(name));
}
}
Now at some point in your code when you do BoundInternal = _internal, anything bound to it will be informed of the change.
Every ItemsControl has a, Items property which has a Refresh() method that you can call, which will update your list.
MyList.Items.Refresh()

Categories

Resources