Issue
I want to be able to check a property from another View Model to see if it has values in it, if it does do something and vise versa.
Code
So in View Model A (OnDemandMainViewModel is the class name) I have a property which holds all the items inside of a Timeline:
public ObservableCollection<ITimeLineDataItem> Timeline2Items
{
get { return _timeline2Items; }
set
{
_timeline2Items = value;
OnPropertyChanged("Timeline2Items");
}
}
private ObservableCollection<ITimeLineDataItem> _timeline2Items;
Then in View Model B (WizardViewModel is the class name) I want to be able run an if statement to check if that property has any items:
if (//CHECK FOR ITEMS)
{
}
How would I be able to check to see if the property has any items or not?
You can do something like this (assuming OnDemandMain is your view1 and OnDemandMainViewModel your viewmodel1:
OnDemandMain win=Application.Current.Windows.OfType<OnDemandMain>().FirstOrDefault();
OnDemandMainViewModel vm=(OnDemandMainViewModel)win.DataContext;
vm.Timeline2Items.Count();
Related
I am using MVVM with Galasoft MVVMLight libraries.
I have two models; each has a boolean property and different properties of the same type.
public class Model1 : ObservableObject
{
public EnumPair<YesNoInherit> Model1Property
{
get { return _model1Property; }
set
{
_model1Property = value;
Updated = true
RaisePropertyChanged("Model1Property");
}
}
public bool Updated
{
get { return _updated; }
set
{
_updated = value;
RaisePropertyChanged("Updated");
}
}
}
public class Model2 : ObservableObject
{
public EnumPair<YesNoInherit> Model2Property
{
get { return _model2Property; }
set
{
_model2Property = value;
Updated = true
RaisePropertyChanged("Model2Property");
}
}
public bool Updated
{
get { return _updated; }
set
{
_updated = value;
RaisePropertyChanged("Updated");
}
}
}
The type YesNoInherit is an enum having values No, Yes, and Inherit.
Here is the EnumPair class.
public class EnumPair<T> : ObservableObject where T : struct, IConvertible
{
public T EnumValue
{
get { return _enumValue; }
set
{
if (Type.Equals(value, _enumValue) == false)
{
_enumValue = value;
RaisePropertyChanged();
}
}
}
public string SourceName
{
get { return _sourceName; }
set
{
_sourceName = value;
RaisePropertyChanged();
}
}
}
In my view, I am trying to use a ComboBox to let the user select one of the three enum values, and, in some cases, display custom text. The resource "enumComboBoxTemplate" allows the ComboBox drop-down to show enum descriptions. The converter "inheritanceEnum2Desc" is where the custom text would be applied. "object1" is an instance of "Model1".
<ComboBox ItemTemplate=ItemTemplate="{StaticResource enumComboBoxTemplate}"
EnumSource="enums:YesNoInherit">
<ComboBox.Text>
<MultiBinding Converter="{StaticResource inheritanceEnum2Desc}">
<Binding Path="object1.EnumValue"/>
<Binding Path="object1.SourceName"/>
</MultiBinding>
</ComboBox.Text>
</ComboBox>
"Model2" would be used in future programming employing similar functionality, but with different data.
When I change the selection in the ComboBox, I want to change the value of "Updated" (from false to true) so I can enable a button in the view. This appears to require that the EnumPair class somehow make the program execute the setter for Model1Property. Since the two model classes have properties of type EnumPair, I don't believe I can add any code in EnumPair specific to either model class.
How can I accomplish this? I would greatly appreciate any assistance.
Basically, you have two options: either use some kind of message-bus to update the other model (Prism has EventAggregator, not sure about MVVMLight) or make both model instances forward their properties to a common data source that notifies all of its users when a property changes.
If you want to be able to easily change from one class to another in the future without rewriting all of your code, you need to create an Interface that defines all of the things that the two models have in common, and both model classes need to implement the interface. You could call the interface IModel1
So, instead of having a "Model1" in your viewmodel, you would have an "IModel1" in your viewmodel instead. You could pass in the same object you are passing in now, which is of type Model1, because it implements the IModel1 interface. When you are ready to switch, pass in a Model2 instead, and it will work without having to rewrite anything in your view or viewmodel. Your setters can be completely different - as long as both models have all of the methods and properties that are required by the interface, you will be OK.
Alternately, if Model2 is exactly like Model1 except that it has "extra stuff," you can make Model2 a derived class which derives from Model1.
Google searching either of those terms should point you toward a good tutorial.
I've a ReactiveList Books and was able to bind it to the grid using reactive UI.
I'm trying to get the selected item from datagrid so that I further query the BookService for more detail and show the details in a different grid or in a rowdetail of the datagrid itself.
My ViewModel has following properties
private ReactiveList<Book> books;
public ReactiveList<Book> Books
{
get
{
return books;
}
set
{
this.RaiseAndSetIfChanged(ref books, value);
}
}
private string selectedBookName;
public string SelectedBookName
{
get
{
return selectedBookName;
}
set
{
this.RaiseAndSetIfChanged(ref selectedBookName, value);
}
}
And the Book object goes like below
public class Book
{
public string Name{get;set;}
public decimal Price{get;set;}
.
.
.//other properties
}
I tried to get the selected book's Name and assign it to a SelectedBookName in the constructor of the viewmodel.
this.WhenAnyObservable(x=>x.Books.ItemChanged).Select(x => selectedBookName= ((Book)x).Name);
But this didn't worked for me. Am I missing something or I need to follow the otherway
It's also possible to bind the datagrid SelectedItem directly to a property in the view model which provides access to the entire object
this.Bind(ViewModel, x => x.SelectedBook, x => x.DataGridBooks.SelectedItem);
If you only want the book name then you can used SelectedValue
Two problems I see:
You are not actually subscribing to the Observable that is listening for changes to the ReactiveList so you won't get any updates. You probably want:
this.WhenAnyObservable(x=>x.Books.ItemChanged).Subscribe(x => selectedBookName= ((Book)x).Name);
If you are assigning to a private member variable then your ReactiveObject never knows that the bound property has changed. More likely you mean to do SelectedBookName = ((Book)x).Name); Notice the capitalization as you should be assigning to the property if you want the change to notify the bindings.
I have a ListView and a GridView that lists users in an application by names. Whenever the user selects an user to edit, I add a new tab to a TabControl, and bind all editable properties to the WPF controls.
However, when the user is editing in the Edit Tab, the information in the List (specifically, the name field) is also being updated.
Currently I'm making a copy of the object to be edited and leaving the original so it doesn't update the ListView, but isn't there a better/easier way to do this?
I've tried setting the Binding Mode=OneWay, didn't work, and also UpdateSourceTrigger=Explicit in the GridView but also didn't work.
Is there any easier way to do this?
Edit: The way I implemented my INotifyPropertyChanged class is part of the issue, since I have this:
public partial class MyTabControl : UserControl
{
public MyTabControl()
{
InitializeComponent();
//Here, DataContext is a List<Users>
//Users being my Model from the Database
//Some of it's properties are bound to a GridView
//User doesn't implement INPC
}
public void OpenTab(object sender, RoutedEventArgs e)
{
User original = (sender as Button).DataContext as User;
// - This will create a new ViewModel below with the User I'm sending
MyTabControl.AddTab(original);
}
}
And my ViewModel of Users is:
public class UserViewModel : INotifyPropertyChanged
{
public User Original { get; private set; }
public string Name { get { return Original.Name; } set { Original.Name = value; OnPropertyChanged("Name"); } }
public UserViewModel(User original)
{
Original = original ?? new User();
}
// - INPC implementation
}
Since my ViewModel is the one reporting the property changes, I didn't expect my original User to report it as well to the GridView.
The Mode=OneWay causes the information flow to go from the bound data entity to the target UI property only, any change to the UI property will not be bound back.
The reason why the UI content is changing is because the underlying property is read/write (i.e. has a getter and a setter) and is notifying any value change (due to the implementation of the INPC interface).
Presuming that it is a list of User objects you've bound to the GridView, you have two simple options to fix this. Which one is best depends on how much scope for change you have:
change the current Name property on the User object, remove the setter for it. Replace the setter with a method to set the property (i.e. SetUserName(string name)) which then sets the private member variable. Or pass the name as an argument to the constructor of the User entity.
create a new property with only a getter which returns the name and set your binding to that; i.e. public string UserName { get { return Name; }}. As there is only a getter there will be no notification of this property, so if the name does change it won't be propagated via this new property.
In a MVP applicaiton if I want to encapsulate a ListBox in a public property so that I could expose the property through an interface to the presenter. I should be able to update the items in the ListBox though this public property. I've tried in several ways to do this
public BindingSource Permission
{
get { return lstGivenPermissions.DataSource; } // Casting error
set { lstGivenPermissions.DataSource = value; }
}
I tried several types for the property like IEnumereble<>, List<> etc. but always either setter or geter shows a casting error.
One option is to have separate properties for get and set.
public ListBox gettingPermission
{
get {return lstGivenPermissions; }
}
public BindingSource Permission
{
set { lstGivenPermissions.DataSource = value; }
}
Is it possible to use a single property in this case or else having two properties is a acceptable solution?
EDIT : I'm using MVP pattern and my requirement is that my presenters are talking to the Views through interfaces. So that if I want one of my presenters to access controllers (like text boxes) in the View, those controllers should be encapsulated in properties. So that I can expose through the interface.
This solved my problem.
public List<string> GivenPermission
{
get { return lstGivenPermissions.Items.Cast<string>().ToList(); }
set { lstGivenPermissions.DataSource = value; }
}
I am working with C# using the MVVM pattern. I have two WPF windows, each with a view model. Basically I need to pass a property of the main view model to the 'child' view model. At the minute, I do this by setting a private variable equal to the new view model in the main view model's constructor, and in doing so passing the property in the constructor of the child view model.
However, there is a dependency property linked to the property as it used as a binding for the selected item in a combobox. Therefore, it is likely to change after the child view model is initialized, but by passing the property in the constructor, the change is not made in my child view model.
So, is there anyway for me to pass the property into the constructor and have it change in the child view model when it does in the main view model? Or would I have to create a property in the child view model which is updated everytime the property in the main view model is set?
Hope that makes sense.
Edit Inside my main view model, I declare the following:
public readonly DependencyProperty CurrentDatabaseManagedProperty = DependencyProperty.Register("CurrentDatabaseManaged", typeof(DatabaseInfo), typeof(MainViewModel));
public DatabaseInfo CurrentDatabaseManaged {
get { return (DatabaseInfo)GetValue(CurrentDatabaseManagedProperty); }
set { SetValue(CurrentDatabaseManagedProperty, value); }
}
public DatabaseInfo CurrentDatabaseManagedSelection {
get { return CurrentDatabaseManaged; }
set {
if (CurrentDatabaseManaged != null &&
(String.Equals(value.Name, CurrentDatabaseManaged.Name, StringComparison.OrdinalIgnoreCase))) return;
CurrentDatabaseManaged = (value.IsUsable ? value : dbm.ReadDatabase(value.FileName));
}
}
Where CurrentDatabaseManagedSelection is the SelectedItem of the combobox. In the constructor of the main view model, I have the following:
_DatabaseVM = new ChildViewModel(CurrentDatabaseManaged);
And the constructor of ChildViewModel looks like this:
public ChildViewModel( DatabaseInfo SelectedDatabase)
{
if (SelectedDatabase != null)
_SelectedDatabase = SelectedDatabase;
}
}
Basically I would like _SelectedDatabase to be updated whenever CurrentDatabaseManagedSelection is.
You have to change the value later, after bindings are set up in the UI.
Use the Dispatcher.BeginInvoke method to put off updating the property until later on.
public MyClass(object someValue)
{
Dispatcher.BeginInvoke(
(Action)(() => Property = someValue), // the cast may not be required
DispatcherPriority.ApplicationIdle); // runs after everything is loaded
}
It looks like you want to bind to the CurrentDatabaseManagedSelection property. The simplest way to simulate this is to add this to the setter of that property:
_DatabaseVM._SelectedDatabase = value;
To do it with actual bindings, you'd need to
make ChildViewModel._SelectedDatabase a dependency property,
make MainViewModel implement INotifyPropertyChanged, and
call the PropertyChanged event in the setter of CurrentDatabaseManagedSelection.
make ChildViewModel extend DependencyObject
instead of just setting the property, set a binding, e.g.
BindingOperations.SetBinding(this, _SelectedDatabaseProperty,
new Binding("CurrentDatabaseManagedSelection") { Source = mainViewModel });