I create an object Custom as you can see below
public class GridViewModel
{
private List _listRowCust = new List();
public List ListRowCust
{
get { return _listRowCust; }
set { _listRowCust = value; }
}
}
public class RowCustom
{
private List<CellCustom> _listCellCustom = new List<CellCustom>();
public List<CellCustom> ListCellCustom
{
get { return _listCellCustom; }
set { _listCellCustom = value; }
}
public RowCustom() { }
}
I try to bind the custom object on the datagrid object available in silverlight4.
I wish to bind any cell on the datagrid. One line should identify by a row object and each cell by a cellCustom.
I use this code
textColumn = new DataGridTextColumn();
textColumn.Header = "RemainingWork";
textColumn.Binding = new Binding("Cell[0]"); //it's a supposed syntax possibility in fact I have 3 rows with 10 cells
GridElements.Columns.Add(textColumn);
GridElements.ItemsSource = e.GridViewModel.ListRowCust;
I don't find any explanation on How to custom the binding.
Do you have any idea?
Thank you
best regards,
Alexandre
I think you can only bind to public properties.
So CellCustom must have a public property to bind to, if that's the object used for the itemsSource, or data context.
Related
I have some trouble with the data binding while using MVVM in Xamarin. Let me explain my architecture:
I have a Manager-class, which contains a ObservableCollection with classes of type t, t is my model class. The Manager-class contains also a attribute called activeT, which is the current selected object of my model class. There are 2 UIs, one which shows the current data of t. The viewModel is bound to the attribute t of my Manager-class like that:
public t CurrentT
{
get
{
return _mgr.CurrentT;
}
set
{
_mgr.CurrentT = value;
OnPropertyChanged();
}
}
_mgr is my singleton Manager-Object.
Now there is the other view, which is able to choose the current t out of a combobox. The viewModel of that view is bound to the ObservableCollection of the manager. If I change the selected object, I do it like with the same code like above. The Property of the manager is the following code:
public t CurrentT
{
get
{
return _currentT;
}
set
{
_currentT= value;
OnPropertyChanged());
}
}
The problem is now, that the first view to view the current selected t does not refresh, though I can see in the debugger, that the current t is changed by the other view.
Can someone help me?
Edit:
I provide some more Code:
The Manager-Class:
public class Manager : INotifyPropertyChanged
{
private t _currentConstructionSite;
private ObservableCollection<t> _constructionSites = null;
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
public t CurrentConstructionSite
{
get
{
return _currentConstructionSite;
}
set
{
_currentConstructionSite = value;
OnPropertyChanged("CurrentConstructionSite");
}
}
public ObservableCollection<t> ConstructionSites
{
get
{
return _constructionSites;
}
set
{
_constructionSites = value;
}
}
private Manager()
{
ConstructionSites = DataRepository.GenConstructionSites();
_currentConstructionSite = ConstructionSites[0];
}
}
The ViewModels Class A (This is the viewmodel of the view, which shows some data):
public class DashboardViewModel : ViewModelBase
{
private Manager _mgr;
public t CurrentConstructionSite
{
get
{
return _mgr.CurrentConstructionSite;
}
set
{
_mgr.CurrentConstructionSite = value;
OnPropertyChanged();
}
}
public DashboardViewModel()
{
_mgr = Manager.getInstance();
}
}
The View A to show some data:
Binding Setup from XAML:
<ContentPage.BindingContext>
<local:DashboardViewModel x:Name="viewModel"/>
</ContentPage.BindingContext>
Binding a Label to show data:
<Label Text="{Binding CurrentConstructionSite.ConstructionSiteName, Mode=TwoWay}" HorizontalOptions="Center" Font="Bold" FontSize="Large"/>
ViewModel B to choose the current t:
public class ChooseConstructionSiteViewModel : ViewModelBase
{
Manager _mgr = null;
public ObservableCollection<t> ConstructionSites
{
get
{
return _mgr.ConstructionSites;
}
}
public t CurrentConstructionSite
{
get
{
return _mgr.CurrentConstructionSite;
}
set
{
_mgr.CurrentConstructionSite = value;
OnPropertyChanged();
}
}
public ChooseConstructionSiteViewModel()
{
_mgr = Manager.getInstance();
}
}
The View to choose the current t:
<combobox:SfComboBox x:Name="combobox" Grid.Row="0" Grid.Column="1" Margin="8,0,20,0" VerticalOptions="Center" HeightRequest="40" DataSource="{Binding ConstructionSites}" DisplayMemberPath="ConstructionSiteName" SelectionChanged="Handle_SelectionChanged"/>
And if the selection from the combobox changed:
void Handle_SelectionChanged(object sender, Syncfusion.XForms.ComboBox.SelectionChangedEventArgs e)
{
t selectedItem = e.Value as t;
_viewModel.CurrentConstructionSite = selectedItem;
}
The two views are contained as contetPages in a tabbedPage. It works in general, but the changing the selected t in the view B does not update the data in view A. I can see in the debugger that the value of t is changed via view B but when I go back to view A there is the old value. In the debugger I can see that the value is updated.
BTW: ViewModelBase is the class which implements INotifyPropertyChanged
From you second viewmodel, you need to "notify" the first viewmodel that the data has changed.
One of the ways to do that, would be to use a Messenger (MvvmLight has one, so does MvvmCross). You can then use the messenger from your Manager, to notify all the viewmodels that need the info, that CurrentT changed.
In the messenger subscription in your viewmodels, simply call a RaiseNotifyPropertyChanged of your property, and you should be good to go
I'm creating a WinForms application with a DataGridView. The DataSource is a ReactiveList. Adding new items to the list however does not update the UI.
ViewModel
public class HomeViewModel: ReactiveObject
{
public ReactiveCommand<object> AddCmd { get; private set; }
ReactiveList<Model> _models;
public ReactiveList<Model> Models
{
get { return _models; }
set { this.RaiseAndSetIfChanged(ref _models, value); }
}
public HomeViewModel()
{
Models = new ReactiveList<Model>() { new Model { Name = "John" } };
AddCmd = ReactiveCommand.Create();
AddCmd.ObserveOn(RxApp.MainThreadScheduler);
AddCmd.Subscribe( _ =>
{
Models.Add(new Model { Name = "Martha" });
});
}
}
public class Model
{
public string Name { get; set; }
}
View
public partial class HomeView : Form, IViewFor<HomeViewModel>
{
public HomeView()
{
InitializeComponent();
VM = new HomeViewModel();
this.OneWayBind(VM, x => x.Models, x => x.gvData.DataSource);
this.BindCommand(VM, x => x.AddCmd, x => x.cmdAdd);
}
public HomeViewModel VM { get; set; }
object IViewFor.ViewModel
{
get { return VM; }
set { VM = (HomeViewModel)value; }
}
HomeViewModel IViewFor<HomeViewModel>.ViewModel
{
get { return VM; }
set { VM = value; }
}
}
The view always show "John".
Debugging Subscribe show added items.
Tried it with ObservableCollection same result.How to use ReactiveList so UI is updated when new items are added
Tried it with IReactiveDerivedList same result. Does ReactiveUI RaiseAndSetIfChanged fire for List<T> Add, Delete, Modify?
I think what you want is a ReactiveBindingList rather than a ReactiveList. This is a WinForms specific version of the ReactiveList for binding purposes.
You should use BindingList.
reference :
"If you are bound to a data source that does not implement the IBindingList interface, such as an ArrayList, the bound control's data will not be updated when the data source is updated. For example, if you have a combo box bound to an ArrayList and data is added to the ArrayList, these new items will not appear in the combo box. However, you can force the combo box to be updated by calling the SuspendBinding and ResumeBinding methods on the instance of the BindingContext class to which the control is bound."
https://learn.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-bind-a-windows-forms-combobox-or-listbox-control-to-data?view=netframeworkdesktop-4.8
Or
ReactiveBindingList
It work fine for me. !!!
I am adding the Property grid control in my project.
I have to show the Drop down box in one field of Property Grid.
Is there any solution to apply this.
You have to declare a type editor for the property in your PropertyGrid and then add to the list of choices. This example creates a Type Converter and then overrides the GetStandardValues() method to provide choices to the drop-down:
private String _formatString = null;
[Category("Display")]
[DisplayName("Format String")]
[Description("Format string governing display of data values.")]
[DefaultValue("")]
[TypeConverter(typeof(FormatStringConverter))]
public String FormatString { get { return _formatString; } set { _formatString = value; } }
public class FormatStringConverter : StringConverter
{
public override Boolean GetStandardValuesSupported(ITypeDescriptorContext context) { return true; }
public override Boolean GetStandardValuesExclusive(ITypeDescriptorContext context) { return true; }
public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
List<String> list = new List<String>();
list.Add("");
list.Add("Currency");
list.Add("Scientific Notation");
list.Add("General Number");
list.Add("Number");
list.Add("Percent");
list.Add("Time");
list.Add("Date");
return new StandardValuesCollection(list);
}
}
The key is the property being assigned a Type Converter in the line:
[TypeConverter(typeof(FormatStringConverter))]
That provides you with the opportunity to introduce your own behavior via overrides.
Here's a simpler example, which allows the Enum type of a Property to automatically provide its values to the PropertyGrid drop-down:
public enum SummaryOptions
{
Sum = 1,
Avg,
Max,
Min,
Count,
Formula,
GMean,
StdDev
}
private SummaryOptions _sumType = SummaryOptions.Sum;
[Category("Summary Values Type")]
[DisplayName("Summary Type")]
[Description("The summary option to be used in calculating each value.")]
[DefaultValue(SummaryOptions.Sum)]
public SummaryOptions SumType { get { return _sumType; } set { _sumType = value; } }
By virtue of the fact that the property is an Enum type, those enum values pass through to become the drop-down options automatically.
I have a number of collection bound to the application main window controls shown in a
simplified form below. There are a number of other elements in the view model
(Ommited for Clarity) which all update and work as expected.
I require to edit a collection's element in another window, with the edited data back in the origonal collection.
/// Example of the Collection and Properties
ObservableCollection<MyData> _MyCollection = new ObservableCollection<MyData>();
public ObservableCollection<MyData> MyCollection { get { return _MyCollection; } }
public class MyData : INotifyPropertyChanged
{
private bool cb_checked;
public string Param1 { get; set; }
public string Param2 { get; set; }
public bool myCheck
{
get { return cb_checked; }
set
{
if (cb_checked == value) return;
cb_checked = value;
RaisePropertyChanged("Checked");
}
}
}
My problem is how do I pass an item of a collection to a new window for editing.
My intal thoughts were to pass the item in the constructor of the window
Dialog.Edit window = new Dialog.Edit(_MyCollection[2] );
window.Owner = this;
window.Show();
I also tried this as I have read I cant use indexed references
var tmp = _MyCollection[2];
Dialog.Edit window = new Dialog.Edit( tmp);
window.Owner = this;
window.Show();
but this does not work and I get null exceptions whe trying to access elements.
If I need to pass the complete collection this is also ok as they are all quite small i.e. < 50 items.
I must be going about this in the wrong way, could someone please explain how to do this
correctly please.
Many Thanks
Sarah
I have a PropertyGrid control to which I bind a container with an array of complex objects:
// Collection
public class ParametersCollection
{
private ParameterObject [] _parameters = null;
[Category("SubReportParams")]
public ParameterObject [] Parameters
{
get { return _parameters; }
set { _parameters = value; }
}
public ParametersCollection()
{
// _parameters initialization here...
}
}
// Complex object
public class ParameterObject
{
private string _name = "";
private string _value = "";
[Category("Information"), DisplayName("Name")]
public string Name
{
get { return _name; }
set { _name = value; }
}
[Category("Information"), DisplayName("Value")]
public string Value
{
get { return _value; }
set { _value = value; }
}
}
Everything works fine, except two cases:
In example, if array _parameters has only 2 items, default array size is 4 and items with indexes 2 and 3 are nulls. PropertyGrid displays these items as empty fields. How to force PropertyGrid to ignore these fields and simply not displaying it?
_parameters variable is an array type, so _parameters items are displayed with their indexes from 0 to n. Is there a posibillity to display them with their names from property ParamObject.Name instead of their indexes from an array?
For the fist question, the easiest way is to add a "fake" property computed from the "real" property. It's not perfect, but you can use various attribute to help:
DisplayName to give the fake property the name of the real property
Browsable(false) instructs the property grid to skip the real property
EditorBrowsable(never) instructs Visual Studio's intellisense to not show this property in external code.
[Browsable(false)]
public ParameterObject[] Parameters
{
get { return _parameters; }
set { _parameters = value; }
}
[Category("SubReportParams"), DisplayName("Parameters")]
[EditorBrowsable(EditorBrowsableState.Never)]
public ParameterObject[] NonEmptyParameters
{
get
{
return _parameters.Where(p => p != null).ToArray();
}
}
For the second question, one simple way is to add a ToString() implementation like this:
public class ParameterObject
{
public override string ToString()
{
return Name;
}
}
Otherwise, you can to add a custom TypeConverter to the class.