How to make custom property of Linq2SQL class bindable? - c#

My Database has a Table Foo with the Property IsTrue.
I made a Linq2SQL Class "myData.dbml" for this Database and added the generated Foo-Class to my Datasources bar.
I have a Simple Winforms Window with a ToggleButton which should bind to the inverse of IsTrue.
To achieve this I tried to add the Property NotTrue to the myData.dbml but this caused an SQLException, invalid row name "NotTrue".
I tried to add the Property Code to the myData.cs like this:
public bool NotTrue {
get {
return !this._IsTrue;
}
set {
if (this._IsTrue == value) {
this.OnIsTrueChanging(!value);
this.SendPropertyChanging();
this._IsTrue = !value;
this.SendPropertyChanged("IsTrue");
this.SendPropertyChanged("NotTrue");
this.OnIsTrueChanged();
}
}
}
But then the Property didnt appear when adding Foo to Datasources even when adding [Bindable(true)]
What worked, was binding to IsTrue and negating the Binding with this:
private void InvertBoolBinding(ControlBindingsCollection collection,string property) {
foreach (Binding b in collection) {
if (b.PropertyName.Equals(property)) {
ConvertEventHandler invert = new ConvertEventHandler((sender, e) => { e.Value = !((bool)e.Value); });
b.Format += invert;
b.Parse += invert;
}
}
}
Called like this:
InvertBoolBinding(lockToggleButton.DataBindings, "IsChecked");
Though in my main project there's a huge amount of those Bindings, this approach is quite a hassle. It seems that Datasources isn't able to connect properties through partial classes. When I add the property to the myData.designer.cs, it is found. But this class get regularly regenerated and my property gets lost.
So maybe I need a completely different approach or maybe theres a way to make partial class extensions work.
I hope you got some idea on that. Thanks!

Moving the Linq2SQL class to a different assembly makes Visual Studio resolve the partial connection.
Found here.

Related

Is there a way to easily bind data to UI in runtime

Context
So after researching a bit about UI toolkit, i decided to use it for my project as i am very used to CSS and i despise the "default/legacy" UI system Unity3D offers.
Unfortunately its on a very early stage of development and they seem to be taking it in a "editor GUI" direction. Regardless i choose it as it made designing the UI, way faster than i could ever do with the usual "Unity3D UI" method of doing things.
Objective
My objective is relatively simple, i want to create a behavior that updates the UI based on some variable while hiding/abstracting this behavior(in other words i want to bind the value of the UI to some integer on a data class).
In the future this will be further complicated due to me slowly migrating everything to a multiplayer context
Main Problem
After hours of searching/reading the documentation, and brute forcing my way into the problem, i managed to reach to a simple solution, which i will abreviate due to me hardcoding some very similar behaviour:
GameObject trackCanvas = GameObject.Find("Canvas");
UIDocument docum= trackCanvas.GetComponent<UIDocument>();
Label foodUI = docum.rootVisualElement.Q<Label>(name: "FoodVar");
if(playerResources!= null){
SerializedObject pR = new SerializedObject(playerResources);
SerializedProperty foodProp = pR.FindProperty("food");
foodUI.BindProperty(foodProp);
}else{
foodUI.Unbind();
}
Pretty simple solution and better yet i saved some thinking time. It all worked like a charm until i try to build it and... I see multiple errors relating to importing UnityEditor which i started removing it(since i pretty much import everything and only on CleanUp i start to see whats necessary or not)
Unfortunately on this very script i couldnt and after rereading the documentation on the fine print(which wasnt so fine...) i read that SerializedObject can't be used in "production/runtime/build" version because it depended on UnityEditor which wouldnt exist on the finalized product.
Which really annoyed me because it was a very eloquent solution.
Suffix
The manual seems to suggest there is ways to go around using UnityEditor namespace. Unfortunately from their very vague tutorial i wasnt able to figure out how it works(im mentioning the tank example which only seems to use unityeditor because they wanted to be able to bind stuff on edit mode, while the binding itself seems to be done through uxml)
I've tried a few things but it all seemed out of context like having some serializedField would magically bind with uxml just because the binding path was the same as variable name
Then i thought well if unity doesnt want me to use editor stuff in runtime mode ill just force it so It shouldnt be that hard to just copy paste some of its class's and then somehow hack it. Unfortunetely Unity not only has a strict proprietary license that doesnt allow you to modify its software in anyway, but some of the annotations, functions, etc... were protected(especially the C stuff that they use)
Then i thought about doing it by hand and i arrived at two options:
Just put food.value = resources.food in some kind of update and hope it doesnt create any kind of issues when i migrate it to a multiplayer context
Or do something more complicated like some kind of delegate i would call that would update the UI, being more efficient in theory due to me only updating whats needed to.
Since im doing an RTS, i think the values will be changing constantly, so im very divided on both. Making me want to stick to the solution that was already done
This is all the more stressful when i hate how the documentation is structured, how difficult it is to go around the source code, and the worse how it feels like the documentation goes in length for behavior that is very similar to CSS
TL;DR:
Is there an alternative to BindProperty() in UI toolkit that doesn't rely on Unity Editor?
You could create a wrapper class to hold your values, which could invoke an event whenever the wrapped value changes.
public interface IProperty<T> : IProperty
{
new event Action<T> ValueChanged;
new T Value { get; }
}
public interface IProperty
{
event Action<object> ValueChanged;
object Value { get; }
}
[Serializable]
public class Property<T> : IProperty<T>
{
public event Action<T> ValueChanged;
event Action<object> IProperty.ValueChanged
{
add => valueChanged += value;
remove => valueChanged -= value;
}
[SerializeField]
private T value;
public T Value
{
get => value;
set
{
if(EqualityComparer<T>.Default.Equals(this.value, value))
{
return;
}
this.value = value;
ValueChanged?.Invoke(value);
valueChanged?.Invoke(value);
}
}
object IProperty.Value => value;
private Action<object> valueChanged;
public Property(T value) => this.value = value;
public static explicit operator Property<T>(T value) => new Property<T>(value);
public static implicit operator T(Property<T> binding) => binding.value;
}
After this you could create custom extension method similar to Unity's own BindProperty which works with this wrapper instead of a SerializedProperty.
public static class RuntimeBindingExtensions
{
private static readonly Dictionary<VisualElement, List<(IProperty property, Action<object> binding)>> propertyBindings = new Dictionary<VisualElement, List<(IProperty property, Action<object> binding)>>();
public static void BindProperty(this TextElement element, IProperty property)
{
if(!propertyBindings.TryGetValue(element, out var bindingsList))
{
bindingsList = new List<(IProperty, Action<object>)>();
propertyBindings.Add(element, bindingsList);
}
Action<object> onPropertyValueChanged = OnPropertyValueChanged;
bindingsList.Add((property, onPropertyValueChanged));
property.ValueChanged += onPropertyValueChanged;
OnPropertyValueChanged(property.Value);
void OnPropertyValueChanged(object newValue)
{
element.text = newValue?.ToString() ?? "";
}
}
public static void UnbindProperty(this TextElement element, IProperty property)
{
if(!propertyBindings.TryGetValue(element, out var bindingsList))
{
return;
}
for(int i = bindingsList.Count - 1; i >= 0; i--)
{
var propertyBinding = bindingsList[i];
if(propertyBinding.property == property)
{
propertyBinding.property.ValueChanged -= propertyBinding.binding;
bindingsList.RemoveAt(i);
}
}
}
public static void UnbindAllProperties(this TextElement element)
{
if(!propertyBindings.TryGetValue(element, out var bindingsList))
{
return;
}
foreach(var propertyBinding in bindingsList)
{
propertyBinding.property.ValueChanged -= propertyBinding.binding;
}
bindingsList.Clear();
}
}
Usage:
public class PlayerResources
{
public Property<int> food;
}
if(playerResources != null)
{
foodUI.BindProperty(playerResources.food);
}
UPDATE: Added also extension methods for unbinding properties and made BindProperty immediately update the text on the element.

Windows Forms data binding

So, my question is about the exact methodology behind windows form data binding.
I wrote a simple code, where i created a View, an IViewModel interface and a ViewModel.
interface IVM
{
}
and
public class Vm : IVM
{
int number;
public int Number
{
get
{
return this.number;
}
set
{
this.number = value;
}
}
}
the form looks like:
public partial class Form1 : Form
{
private IVM vm;
public Form1()
{
InitializeComponent();
this.vm = new Vm();
this.iVMBindingSource.DataSource = this.vm;
}
}
and the related designer part is:
this.textBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.iVMBindingSource, "Number", true));
...
this.iVMBindingSource.DataSource = typeof(WindowsFormsApplication1.IVM);
You can clearly see that IViewModel interface does not publish a Number property, but the concrete ViewModel class has a Number property.
Although in design time i can't use the designer to bind the property (since IVM has no Number prop), i can manually write "iVMBindingSource - Number" into the textbox's Test property, to bind it.
My question is, how does binding work EXACTLY? Why don't I receive a runtime error, while trying to access IVM's not existing Number property?
(I tested and it actually changes the VM's Number prop properly)
Does it use some kind of reflection? How does this "magic" binding string works?
Thanks for your answers!
Jup it's done by reflection. I just checked the code and the binding is done by the Binding class. There is a method called CheckBindings which ensures the property you want to bind on is available. It basically works like this:
if (this.control != null && this.propertyName.Length > 0)
{
// ...certain checks...
// get PropertyDescriptorCollection (all properties)
for (int index = 0; index < descriptorCollection.Count; ++index)
{
// select the descriptor for the requested property
}
// validation
// setup binding
}
As Ike mentioned, you can find the source code here:
http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Binding.cs,3fb776d540d0e8ac
MSDN Reference: https://msdn.microsoft.com/en-us/library/system.windows.forms.binding(v=vs.110).aspx
As derape already mentioned, Binding uses reflection. It must use reflection because it cannot know anything about the class you are using. The evaluation will be done at runtime. Since your concrete type Vm got the specified property Number, reflection will return it and Binding class is satisfied. Binding is really flexible as long as the property name is valid.
On the other hand, when you are using the designer, it cannot know which concrete type you will use. Therefore it only allows you to use properties of the common base IVM. If you enter the string manually, design time evaluation will be skipped and input is passed to the binding constructor.
If you want to use designer support, just use the the concrete type or if you don't know the concrete type but need the property Number, simply create a new interface and derive from IMV.

Binding sub properties MvvmCross

Does mvvmcross natively support binding to nested properties?
For example I have a view model as follows:
class MainViewModel : MvxViewModel
{
public SubViewModelBase SubViewModel
{
get { return _subViewModel; }
set { _subViewModel = value; RaisePropertyChanged(() => SubViewModel); }
}
}
The sub view model may change, but the MainView will bind to the same properties for ALL SubViewModelBase classes... an example SubViewModelBase class as follows:
class SubViewModelBase : MvxViewModel
{
public bool ShowIndeterminantProgress
{
get { return _showIndeterminantProgress; }
set { _showIndeterminantProgress = value; RaisePropertyChanged(() => ShowIndeterminantProgress);}
}
// ... More common properties ...
}
So the MainView would ideally bind like this
this.CreateBinding(_progressBar)
.For(view=> view.Visibility)
.To<MainViewModel>(vm => vm.SubViewModel.ShowIndeterminantProgress)
.WithConversion("Visibility")
.Apply();
Should this work? It doesn't appear to be working, but there are no binding errors in the output?
Does mvvmcross natively support binding to nested properties?
Yes
Should this work?
Yes
For example, this line in ApiExamples for Xamarin.iOS is working:
set.Bind(errorLabel2).To(vm => vm.Errors.Count);
https://github.com/MvvmCross/MvvmCross-Tutorials/blob/master/ApiExamples/ApiExamples.Touch/Views/FirstView.cs#L361
The set of supported functionality is described in https://github.com/MvvmCross/MvvmCross/wiki/Databinding#fluent - but admittedly this fluent binding is more established/used in Xamarin.iOS than it is in Wpf.
To try to debug why your current binding might not be working try adding a simple property to your view which provides debug output
private Visibility _mockVisibility;
public Visibility MockVisibility
{
get
{
return _mockVisibility;
}
set
{
Debug.WriteLine("MockVisibility called with " + value);
_mockVisibility = value;
}
}
and binding this as:
this.CreateBinding(this)
.For(view=> view.MockVisibility)
.To<MainViewModel>(vm => vm.SubViewModel.ShowIndeterminantProgress)
.WithConversion("Visibility")
.Apply();
This should give you debug/trace output and should give you somewhere to put a breakpoint to understand the call stack a little too (although expect this to contain lots of reflection which can be hard to read through).
Beyond this:
you could also try binding a label's text to see what that displays.
you can also try setting the binding trace level to Diagnostic (using the static field MvxBindingTrace.TraceBindingLevel https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.Binding/MvxBindingTrace.cs#L14)
try isolating the problem piece by piece (isolating the converter, isolating the nested property, etc, etc) - I guess this is what you are already doing in asking this question.

Dynamic Auto updating (to UI, Grid) binding list in C# Winform?

I'm not even sure if I'm doing this correctly. But basically I have a list of objects that are built out of a class/interface. From there, I am binding the list to a DataGridView that is on a Windows Form (C#)
Here the list is a Sync list which will auto update the UI, in this case DataGridView.
Every thing works fine now, but now i would like to have the List should have an dynamic object, that is the object will have by default two static property (ID, Name), and at run time user will select remaining properties. These should be bind to the data grid. Any update on the list should be auto reflected in the grid.
I am aware that, we can use dynamic objects, but i would like to know , how to approach for solution,
datagridview.DataSource = myData; // myData is AutoUpdateList<IPersonInfo>
Now IPersonInfo is the type of object, need to add dynamic properties for this type at runtime.
public class AutoUpdateList<T> : BindingList<T>
{
private ISynchronizeInvoke _SyncObject;
private Action<ListChangedEventArgs> _FireEventAction;
public AutoUpdateList()
: this(null)
{
}
public AutoUpdateList(ISynchronizeInvoke syncObject)
{
_SyncObject = syncObject;
_FireEventAction = FireEvent;
}
protected override void OnListChanged(ListChangedEventArgs args)
{
try
{
if (_SyncObject == null)
{
FireEvent(args);
}
else
{
_SyncObject.Invoke(_FireEventAction, new object[] { args });
}
}
catch (Exception)
{
// TODO: Log Here
}
}
private void FireEvent(ListChangedEventArgs args)
{
base.OnListChanged(args);
}
}
Could you help out on this?
I guess the best way for you is 'to simulate' the properties. I guess the best way would be the ITypedList implementing, the great example is here.
Once I faced similar issue. For my case I've taken this approach. This just might be helpful for you.
Also, there is a way (it's not about anything 'dynamic') to have a base class with fulls set of properties you gonna use. But it won't work if you don't have all properties before the runtime.

WPF: Replacing databound collection contents without Clear/Add

When using WPF databinding, I obviously can't do something along the lines of MyCollection = new CollectionType<Whatever>( WhateverQuery() ); since the bindings have a reference to the old collection. My workaround so far has been MyCollection.Clear(); followed by a foreach doing MyCollection.Add(item); - which is pretty bad for both performance and aesthetics.
ICollectionView, although pretty neat, doesn't solve the problem either since it's SourceCollection property is read-only; bummer, since that would have been a nice and easy solution.
How are other people handling this problem? It should be mentioned that I'm doing MVVM and thus can't rummage through individual controls bindings. I suppose I could make a wrapper around ObservableCollection sporting a ReplaceSourceCollection() method, but before going that route I'd like to know if there's some other best practice.
EDIT:
For WinForms, I would bind controls against a BindingSource, allowing me to simply update it's DataSource property and call the ResetBindings() method - presto, underlying collection efficiently changed. I would have expected WPF databinding to support a similar scenario out of the box?
Example (pseudo-ish) code: WPF control (ListBox, DataGrid, whatever you fancy) is bound to the Users property. I realize that collections should be read-only to avoid the problems demonstrated by ReloadUsersBad(), but then the bad code for this example obviously wouldn't compile :)
public class UserEditorViewModel
{
public ObservableCollection<UserViewModel> Users { get; set; }
public IEnumerable<UserViewModel> LoadUsersFromWhateverSource() { /* ... */ }
public void ReloadUsersBad()
{
// bad: the collection is updated, but the WPF control is bound to the old reference.
Users = new ObservableCollection<User>( LoadUsersFromWhateverSource() );
}
public void ReloadUsersWorksButIsInefficient()
{
// works: collection object is kept, and items are replaced; inefficient, though.
Users.Clear();
foreach(var user in LoadUsersFromWhateverSource())
Users.Add(user);
}
// ...whatever other stuff.
}
If the object MyCollection is of implements INotifyPropertyChanged, you can simply replace the collection.
An example:
public class MyClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<Whatever> _myCollection;
private void NotifyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
public ObservableCollection<Whatever> MyCollection
{
get
{
return _myCollection;
}
set
{
if (!ReferenceEquals(_myCollection, value))
{
_myCollection = value;
NotifyChanged("MyCollection");
}
}
}
}
With this, when you assign a collection, WPF detects this and everything gets updated.
This is how I'd solve this.
The link below explains how to implement an AddRange method.
http://web.archive.org/web/20150715112054/http://blogs.msdn.com/b/nathannesbit/archive/2009/04/20/addrange-and-observablecollection.aspx
It looks like you're stuck with implementing a sub-class that handles this case correctly.
Apparently, certain controls don't support batched collection change notifications. At least they didn't when that article was written. Though now you should have a bit more information if you want to investigate further.

Categories