I have a lot of static poperties in my class library. I want to bind the property values in grid with two way binding. How can bind it?
public class AllStaticProperty
{
public static int JA{get;set;}
public static float JB{get;set;}
public static bool JC{get;set;}
public static int[] JD=new int[1000];
//More properties here
public static float[] ZZ=new float[2000];
}
I want bind static property name grid first column field and user enter the property value in grid second column then back to store the value in static property. how can I bind( I have more than 3000 static property)
If you want to bind properties and reflect changes to them in the user interface, you have to implement INotifyPropertyChanged in the corresponding class and raise the PropertyChanged event whenever a property changes its value to trigger binding updates in controls to get the latest value.
However, static properties cannot access instance methods, so how should they raise property changed notifications? There are ways to achieve this, as you can see in this related post, but it is bad design. Another issue here is to bind a static property of a non-static class two-ways, but there are also workarounds.
I recommend to overthink your design and create view models that implement INotifyPropertyChanged, e.g.:
public class SampleViewModel : INotifyPropertyChanged
{
private int _ja;
public int JA
{
get => _ja;
set
{
if (_ja == value)
return;
_ja = value;
OnPropertyChanged();
}
}
// ...other properties and backing fields.
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Then you can bind a property with the usual syntax and add Mode=TwoWay if that is not the default already.
SomeProperty="{Binding JA, Mode=TwoWay}"
An alternative option is to create one or more wrapper view models that are implemented as above, but access the static properties of your AllStaticProperty class, but then you need to synchronize the view model with the static properties, too, if any static property changes.
Related
I apologize for the lengthy question, but I feel like it is necessary to include all of this information.
Until now, I've been using a possibly-unorthodox way of adding UserControls to my applications. Let's say I have a UserControl called Diagnostics that has a button, that when clicked, performs a function that is specific to the application that owns it. For example, if I drop Diagnostics into AppA, I want it to display "A", and if I drop it into AppB, I want AppB to define the behavior so it displays "B".
I typically implement this via a callback interface that is passed to the UserControl's constructor, which is pretty straightforward. Here's some sample "code" that probably won't compile, but is presented just to clarify what I've basically done before, and what I am trying to do:
public interface IDiagnosticsCallback {
void DisplayDiagnostics(); // implemented by owner of Diagnostics UserControl
}
public class MyApp : IDiagnosticsCallback {
public void DisplayDiagnostics() {
MessageBox.Show("Diagnostics displayed specifically for MyApp here");
}
}
public Diagnostics : UserControl {
private IDiagnosticsCallback _callback { get; private set; }
public Diagnostics(IDiagnosticsCallback callback) {
_callback = callback;
}
public void ShowDiagnostics_Click(object sender, EventArgs e) {
_callback.DisplayDiagnostics();
}
}
The problem I had in the past was understanding how to declare a UserControl that takes a parameter in its constructor (i.e. doesn't have a default constructor) in XAML, and apparently you can't. I worked around this with a fairly-inelegant method -- I would give the main panel a name in XAML, and then from code-behind I would create Diagnostics, passing it the necessary callback, and then I would add Diagnostics to the panel's list of children. Gross and violates usage of MVVM, but it works.
This weekend, I decided to try to learn how to do it for a class and a TextBox, and it turns out that all I had to do was to create a DependencyProperty in my UserControl and use databinding. It looks something like this:
public ClassA
{
public void ShowSomethingSpecial()
{
MessageBox.Show("Watch me dance!");
}
}
public MyApp
{
public ClassA Foo { get; set; }
}
public Diagnostics : UserControl
{
public static readonly DependencyProperty SomethingProperty = DependencyProperty.Register("Something", typeof(ClassA), typeof(Diagnostics), new PropertyMetadata());
public ClassA Something
{
get { return (MyApp)GetValue(SomethingProperty); }
set { SetValue(SomethingProperty, value); }
}
// now uses default constructor
public void ShowSomethingSpecial_Click(object sender, EventArgs e)
{
Something.ShowSomethingSpecial();
}
}
MyApp.xaml
<diags:Diagnostics Something="{Binding Foo}" />
So Foo is a property of MyApp, which is databound to the Something DependencyProperty of Diagnostics. When I click the button in the UserControl, the behavior is defined by ClassA. Much better, and works with MVVM!
What I'd like to do now is to go one step further and instead pass a callback interface to my UserControl so that it can get the states of my digital inputs and outputs. I'm looking for something like this:
public Diagnostics : UserControl
{
public interface IDioCallback
{
short ReadInputs();
short ReadOutputs();
void SetOutput( char bit);
}
public IDioCallback DioCallbackInterface {
get { return (IDioCallback)GetValue(DioCallbackInterfaceProperty); }
set { SetValue(DioCallbackInterfaceProperty,value); }
}
// Using a DependencyProperty as the backing store for DioCallbackInterface. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DioCallbackInterfaceProperty = DependencyProperty.Register("DioCallbackInterface",typeof(IDioCallback),typeof(Diagnostics),new PropertyMetadata(0)); // PropertyMetadata is the problem...
}
public class DIO : IDioCallback
{
public short ReadInputs() { return 0; }
public short ReadOutputs() { return 0; }
public void SetOutput( char bit) {}
}
public class MyApp
{
public DIO MyDIO { get; set; }
}
MyApp.xaml
<diags:Diagnostics DioCallbackInterface="{Binding MyDIO}" />
While my code (maybe not the exact code above, but my real project) does compile successfully, it appears that the PropertyMetadata passed to Register is at fault. I get an exception that says "Default value type does not match type of property 'DioCallbackInterface'."
Am I doing something really unorthodox, or is this approach to databinding interfaces actually possible? If not, what are the recommended ways of defining how a UserControl behaves based on the application it's being used in?
The exception you have mentioned because of this:
new PropertyMetadata(0)
You have passed 0 (of type Int32) instead of the null or whatever you like for your interface: IDioCallback.
I cannot say that the way you select is wrong, but you should keep in mind that every user of your UserControl must implement that interface you have defined. If you have several properties that you would like to pass to the UserControl, you can basically discard them via DependencyProperty.
In your case you also would like to inject some logic to the UserControl Button. Let me suppose that this control has only one button. MVVM-way to handle Button.Click event is done via ICommand - you can declare the command property in your ViewModel and use it as data source for data binding in your UserControl as DependencyProperty, passing it properly to the Button.
Also you can have an agreement with all of your data context, and use special name for that property. For example:
public interface IViewModelWithCommand
{
public ICommand TheCommand { get; }
}
Implement it for each data context you need, and use TheCommand property name inside your data template of your UserControl. In the code-behind you can create type validation of DataContext passed to your UserControl, and throw an exception in case the type is not implements your interface
Here several articles you probably should be interested in:
RelayCommand
Commands, RelayCommands and EventToCommand
How to use RelayCommands
Using RelayCommand will simplify your life because you don't need to re-implement interface for every command, instead, you need to pass valid action that you want.
Is there a way to bind directly to a Collection in the model and manually tell WPF that the binding needs refreshing without having to create an ObservableCollection for it in the viewmodel?
<ListBox ItemsSource="{Binding Position.PossibleMoves}">
...
</ListBox>
Position is my model, part of a chess library, and PossibleMoves is a Collection within it. I do not want to implement INotifyProperty changed or put ObservableCollections in a stand alone optimized library.
I want to avoid copying PossibleMoves into an ObservableCollection every time the position is updated. The data binding works on initialization but it would be handy if I could also refresh the binding at will inside the viewmodel.
Calling OnNotifyPropertyChanged("Position.PossibleMoves") from the viewmodel doesn't work because the reference to the collection itself does not change.
You can do this by using an attached behavior to bind a handler to an event that gets triggered in the view model. You can't bind directly to events though so you have to wrap them in a class like so:
public class Refresher
{
public delegate void RefreshDelegate();
public event RefreshDelegate Refresh;
public void DoRefresh()
{
if (this.Refresh != null)
this.Refresh();
}
}
Now add an instance of that to your view model:
public class MyViewModel
{
public IList<string> Items { get; set; }
private Refresher _Refresher = new Refresher();
public Refresher Refresher {get {return this._Refresher;}}
}
Next create an attached behavior that registers a delegate instance with that event and forces the listbox to refresh its binding:
public static class RefreshBehavior
{
public static readonly DependencyProperty RefresherProperty = DependencyProperty.RegisterAttached(
"Refresher",
typeof(Refresher),
typeof(RefreshBehavior),
new PropertyMetadata(null, OnRefresherChange));
public static void SetRefresher(DependencyObject source, Refresher value)
{
source.SetValue(RefresherProperty, value);
}
public static Refresher GetRefresher(DependencyObject source)
{
return (Refresher)source.GetValue(RefresherProperty);
}
private static void OnRefresherChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Refresher.RefreshDelegate handler = () =>
{
var listBox = d as ListBox;
listBox.Items.Refresh();
};
if (e.NewValue != null)
(e.NewValue as Refresher).Refresh += handler;
if (e.OldValue != null)
(e.OldValue as Refresher).Refresh -= handler;
}
}
And finally attach it to your listbox in the xaml:
<ListBox ItemsSource="{Binding Items}"
local:RefreshBehavior.Refresher="{Binding Refresher}"/>
That's it. Call Refresher.DoRefresh() in your view model and it will force a listbox update.
This works but it's really hammering a square peg into a round hole. If I were you I'd do everything I could to try and do proper collection changed notification in your view model. I understand you wanting to keep ObservableCollection out of your model but there are ways to proxy change notification automatically (e.g. Castle DynamicProxy).
You need to NotifyPropertyChange for the PossibleMoves from inside the Position class or make a property that delegates to the Position.PossibleMoves and notify that one.
I have some nested view models that implement INotifyPropertyChanged. I'd like to bind an event listener to a nested property path (e.g. "Parent.Child.Name"), much like FrameworkElement dependency properties can be bound to arbitrary nested properties.
However, I just want something like a PropertyChanged event listener -- I don't actually have any UI element I'd like to bind. Is there any way to use the existing framework to set up such an event source? Ideally, I shouldn't need to modify my view model classes (as this is not required for regular data binding in Silverlight).
You can certainly co-opt the binding/dependency-property infrastructure to listen for changes to a nested property. The code below is WPF but I believe you can do something similar in Silverlight:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new Parent { Child = new Child { Name = "Bob" } };
this.SetBinding(ChildNameProperty, new Binding("Child.Name"));
}
public string ChildName
{
get { return (string)GetValue(ChildNameProperty); }
set { SetValue(ChildNameProperty, value); }
}
// Using a DependencyProperty as the backing store for ChildName. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ChildNameProperty =
DependencyProperty.Register("ChildName", typeof(string), typeof(MainWindow), new UIPropertyMetadata(ChildNameChanged));
static void ChildNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MessageBox.Show("Child name is now " + e.NewValue);
}
}
So I've defined my own DependencyProperty, not part of any UI per se (just the MainWindow class), and bound "Child.Name" to it directly. I'm then able to be notified when Child.Name changes.
Will that work for you?
I'm not quite sure if I've got the right grasp on this or not, what I've read seems to agree with what I'm trying to do, however It doesn't seem to be working.
If I add an additional owner to a dependency property of a class, whenever the orig class dp changes, the change should get propagated to the additional owner, correct?
What I have is a custom control, which I want to set a property on, and then on certain objects that are within the custom control data template inherit this property value.
public class Class1: DependencyObject{
public static readonly DependencyProperty LongDayHeadersProperty;
public bool LongDayHeaders {
get { return (bool)GetValue(LongDayHeadersProperty); }
set { SetValue(LongDayHeadersProperty, value); }
}
static Class1(){
LongDayHeadersProperty = DependencyProperty.Register("LongDayHeaders", typeof(bool), typeof(Class1),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
}
}
public class Class2: DependecyObject{
public static readonly DependencyProperty LongDayHeadersProperty;
public bool LongDayHeaders{
get{ return(bool)GetValue(LongDayHeadersProperty); }
set{ SetValue(LongDayHeadersProperty, value); }
}
static Class2(){
LongDayHeadersProperty = Class1.LongDayHeadersProperty.AddOwner(typeof(Class2));
}
}
But if I assign a DependencyPropertyDescriptor to both properties, it only fires for the Class1 and Class2 doesn't change.
Have I missed something in my understanding?
UPDATE
After some testing, I'm not even sure if my child control is considered a child control within the logical or visual tree. I think it is, but the lack of success leads me to believe otherwise.
There a many class2's which exist in an observable collection of class1. This, to me, makes them childs of class1? But even if I use RegisterAttach on class2, and set the property in class1, it doesn't seem to have any effect?
As MSDN states, the Inherits flag only works when you use RegisterAttached to create the property. You can still use the property syntax for the property.
Update
For clarity, here is how I would define the properties:
public class Class1 : FrameworkElement
{
public static readonly DependencyProperty LongDayHeadersProperty =
DependencyProperty.RegisterAttached("LongDayHeaders",
typeof(bool),
typeof(Class1),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
public bool LongDayHeaders
{
get { return (bool)GetValue(LongDayHeadersProperty); }
set { SetValue(LongDayHeadersProperty, value); }
}
}
public class Class2: FrameworkElement
{
public static readonly DependencyProperty LongDayHeadersProperty =
Class1.LongDayHeadersProperty.AddOwner(typeof(Class2));
public bool LongDayHeaders
{
get{ return(bool)GetValue(LongDayHeadersProperty); }
set{ SetValue(LongDayHeadersProperty, value); }
}
}
If you want your children to be logical children of your control, you need to call the AddLogicalChild. Also, you should expose them through the LogicalChildren property. I must also point out that both classes must derive from FrameworkElement or FrameworkContentElement, as the logical tree is only defined for these elements.
Since you are using an ObservableCollection, you would handle the collection changed events and Add/Remove the children depending on the change. Also, the LogicalChildren property can just return your collection's enumerator.
You are confusing DependencyProperties with Attached (Dependency) Properties.
A DP is for when a class wants bindable, stylable etc properties on itself. Just like .NET properties, they are scoped within their classes. You can register for a property changed event on individual objects, but not globally. TextBox.Text is an example of this. Note that Label.Text is unrelated to TextBox.Text.
An AP is for when a class wants to decorate another object with additional properties. The class that declares the AP is able to listen for property changed events on ALL instances of other objects that have this AP set. Canvas.Left is an example of this. Note that you always have to qualify this setter: <Label Text="Hi" Canvas.Left="50"/>
Currently I have use the following approach to setup change notification on any of my properties that I bind to in xaml:
class MyClass : INotifyPropertyChanged
{
string name;
public string Name
{
get { return name; }
set
{
name = value;
NotifyPropertyChanged("Name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
However, I've seen that to implement a dependency property I need to do stuff like registering it and setting callbacks etc, which in turn will just end up calling the above code.
So what's the point of setting all the extra boiler plate stuff for dependency properties when I can just use the above approach?
Thanks.
Dependency properties can be the target of a binding, whereas regular CLR properties can't. That's why the properties of a control (binding target) are usually dependency properties, whereas the properties of a model or ViewModel class (binding source) are not.
What you are doing is correct (assuming I understand it correctly) dependency properties are not for the things you bind to in the model they are for the properties in controls that the model will be bound to - for example the Text property in a text box.
There are a number of reasons to use them in your custom controls, not least of which is the automatic plumbing that comes with them so that they will correctly bind to a property declared as in your example.