Bind a class collection property via xaml - c#

This is my Globals class
public class Globals
{
private static Globals instance = new Globals();
protected Globals()
{
}
public static Globals Instance
{
get { return instance; }
}
public TrackList Tracklist = new TrackList();
}
This is TrackList in a smart code:
public class TrackList : SettingAttribute {
public TrackList()
{
this.tracks = new ObservableCollectionExt<Track>();
}
protected ObservableCollectionExt<Track> tracks;
public ObservableCollectionExt<Track> Tracks
{
get
{
return tracks;
}
}
public class Track : ICloneable
{
protected Track()
{
// Track instance is achieved by GetTrack
}
public GetTrack(string path)
{
// code implementation here
}
}
}
I wish to bind Globals.Instance.Tracklist.Tracks in a ListView using XAML.
Via runtime, is really easy using ItemSource property
lv.ItemsSource = Globals.Instance.Tracklist.Tracks;
but using xaml I tried with several codes but none is good.

ItemsSource="{Binding Tracklist.Tracks, Source={x:Static local:Globals.Instance}}"
Tracklist has to be a property. Change your Globals class to:
public class Globals
{
private static Globals instance = new Globals();
protected Globals()
{
Tracklist = new TrackList();
}
public static Globals Instance
{
get { return instance; }
}
public TrackList Tracklist { get; private set; }
}

In you view model create Property with type Globals as follows:
property Globals Globals {get;set;}
In XAML bind to it:
<ListView ItemsSource="{Binding Path=Globals.Instance.Tracklist.Tracks}">

Related

How to access a variable declared in a page to a inner class?

I want to access a variable which is declared as public in Main class to a new class created within the same page. I have done like below. But cant access the variable in that class
public sealed partial class MainPage : Page
{
public bool is_arrived = false;
public MainPage()
{
this.InitializeComponent();
bool is_arrived=true;
CallingWebServices asyn_task = new CallingWebServices();
}
public class CallingWebServices
{
//want to access variable "is_arrived" here.
}
}
In such cases you should use constructor injection and pass the value of is_arrived to CallingWebServices.
public sealed partial class MainPage : Page
{
public bool is_arrived = false;
public MainPage()
{
this.InitializeComponent();
bool is_arrived=true;
CallingWebServices asyn_task = new CallingWebServices(is_arrived);
}
public class CallingWebServices
{
private bool _isArrived;
public CallingWebServices(bool isArrived)
{
_isArrived=isArrived;
}
//want to access variable "is_arrived" here.
}
}
One problem with this approach is that is_arrived value will loose sync if you change it in the parent class. So other approach is to pass the reference of the parent class to the inner class.
public sealed partial class MainPage : Page
{
public bool is_arrived = false;
public MainPage()
{
this.InitializeComponent();
bool is_arrived=true;
CallingWebServices asyn_task = new CallingWebServices(this);
}
public class CallingWebServices
{
private MainPage _Instance;
public CallingWebServices(MainPage instance)
{
_Instance=instance;
}
//Access variable "instance.is_arrived" here.
}
}
However such practices should be discouraged and should be eliminated by having a better design approach.

Global Variables in MVVM

I have a multi-page MVVM application that has a few ViewModels. (It's a hobby app, storing statistics and stuff)
The following classes are
GamePageViewModel
MenuViewModel
PlayersViewModel
StartPagePresenter
Controller (This acts as a PageSwitcher and as the model that stores all of my TableAdapters from a database)
All of them have a few of the same variables
Universe
Character
Season
What I'd like to do is move these variables to my MainMenuViewModel (which is the menubar on all of the pages), where you select Universe, Character, Season, etc, and they populate in the other ViewModels.
my MenuViewModel Class
public class MenuViewModel : ObservableObject
{
private DataView _Universes = Controller.UniverseTableAdapter.GetData().DefaultView;
private DataRowView _SelectedUniverse;
public DataView Universes
{
get { return _Universes; }
set
{
_Universes = value;
RaisePropertyChangedEvent("Universes");
}
}
public DataRowView SelectedUniverse
{
get { return _SelectedUniverse; }
set
{
_SelectedUniverse = value;
Controller.SelectedUniverse = _SelectedUniverse;
RaisePropertyChangedEvent("SelectedUniverse");
}
}
public ICommand GoHome { get { return new DelegateCommand(NavigateHome); } }
public ICommand GoPlayers { get { return new DelegateCommand(NavigatePlayers); } }
public ICommand GoGame { get { return new DelegateCommand(NavigateGame); } }
public void NavigateHome() { Controller.Switch(new StartPage()); }
public void NavigatePlayers() { Controller.Switch(new PlayerPage()); }
public void NavigateGame() { Controller.Switch(new GamePage()); }
}
I thought I'd try to store them in the Controller Class like this, but not sure how I would send out the RaisePropertyChangedEvent Events to each of the ViewModels
public static class Controller
{
#region Variables
//Variables
private static MainWindow _Window;
private static MaddenDBDataSet _MaddenDB = new MaddenDBDataSet();
private static CharacterTableAdapter _CharacterTableAdapter = new CharacterTableAdapter();
private static FranchiseTableAdapter _FranchiseTableAdapter = new FranchiseTableAdapter();
private static GamePlayerTableAdapter _GamePlayerTableAdatper = new GamePlayerTableAdapter();
private static GameTableAdapter _GameTableAdapter = new GameTableAdapter();
private static PersonTableAdapter _PersonTableAdapter = new PersonTableAdapter();
private static SeasonTableAdapter _SeasonTableAdapter = new SeasonTableAdapter();
private static UniverseTableAdapter _UniverseTableAdapter = new UniverseTableAdapter();
private static UserYearTableAdapter _UserYearTableAdapter = new UserYearTableAdapter();
private static CollegeTableAdapter _CollegeTableAdapter = new CollegeTableAdapter();
private static view_PlayersTableAdapter _PlayerView = new view_PlayersTableAdapter();
private static view_UniverseCharactersTableAdapter _UniverseCharacterView = new view_UniverseCharactersTableAdapter();
private static UniverseCharacterTableAdapter _UniverseCharacterTableAdapter = new UniverseCharacterTableAdapter();
private static view_ScheduleTableAdapter _ScheduleView = new view_ScheduleTableAdapter();
private static view_YearsTableAdapter _YearView = new view_YearsTableAdapter();
private static View_GameStatsTableAdapter _GameStatsView = new View_GameStatsTableAdapter();
private static view_RegularSeasonTableAdapter _SeasonView = new view_RegularSeasonTableAdapter();
private static view_PlayoffsTableAdapter _PlayoffsView = new view_PlayoffsTableAdapter();
//Keep a tab of all of our ViewModels
private static DataRowView _SelectedUniverse = null;
public static DataRowView SelectedUniverse { get { return _SelectedUniverse; } set { _SelectedUniverse = value; } }
#region Methods
//Navigation
public static void Switch(UserControl newPage)
{
_Window.Navigate(newPage);
}
public static void Switch(UserControl newPage, object state)
{
_Window.Navigate(newPage, state);
}
#endregion
}
Any pointers on storing global variables would be much appreciated!
This is something I did using MvvmCross, with an example for storing selected language (a global var needed). I also use the same pattern for versions, etc. Here is part of my SettingsPreferences class:
public static string SelectedLanguage
{
get { return Settings.AppSettings.GetValueOrDefault(StringConstants.SelectedLanguage, SelectedLanguageDefault); }
set { Settings.AppSettings.AddOrUpdateValue(StringConstants.SelectedLanguage, value); }
}
public static bool FirstRun
{
get { return Settings.AppSettings.GetValueOrDefault(StringConstants.FirstRun, FirstRunDefault); }
set { Settings.AppSettings.AddOrUpdateValue(StringConstants.FirstRun, value); }
}
public static int LatestUpdateVersion
{
get { return Settings.AppSettings.GetValueOrDefault(StringConstants.LatestUpdateVersion, LatestUpdateVersionDefault); }
set { Settings.AppSettings.AddOrUpdateValue(StringConstants.LatestUpdateVersion, value); }
}
public static string LatestUpdateVersionDate
{
get { return Settings.AppSettings.GetValueOrDefault(StringConstants.LatestUpdateVersionDate, LatestUpdateVersionDateDefault); }
set { Settings.AppSettings.AddOrUpdateValue(StringConstants.LatestUpdateVersionDate, value); }
}
Settings is a wrapper to a nuget package for persisting stuff (supports Android, iOS, Windows Store (Windows Phone 8.1 and Windows Store 8.1) and WPF projects):
public static class Settings
{
public static ISettings AppSettings
{
get
{
return CrossSettings.Current;
}
}
}
Now my LanguageViewModel calls it simply like this:
var lang = SettingsPreferences.SelectedLanguage;
To update the setting, simply:
SettingsPreferences.SelectedLanguage = "en";
It can be anything really.

how to use Unity with constructor injection to update the status in parent view of viewmodel1 using the child view & and its viewmodel2 in wpf

This is my UnityResolver Class to create the instance of IUnityContainer
public sealed class UnityResolver
{
private static IUnityContainer _unityContainer;
private static volatile UnityResolver _unityresolverinstance;
private static object syncRoot = new Object();
public static IUnityContainer UnityContainerInitiation
{
get
{
if (_unityContainer == null)
{
if (_unityresolverinstance == null)
{
lock (syncRoot)
{
if (_unityresolverinstance == null)
_unityresolverinstance = new UnityResolver();
}
}
}
return UnityResolver._unityContainer;
}
}
public UnityResolver()
{
_unityContainer = new UnityContainer();
_unityContainer.RegisterType<MaintainRouteViewModel>();
}
}
Below is my Base View and Its ViewModelCode
public partial class MaintainRouteView : UserControl
{
public MaintainRouteViewModel maintainRouteViewModel = null;
IUnityContainer container;
public MaintainRouteView()
{
InitializeComponent();
container = UnityResolver.UnityContainerInitiation;
maintainRouteViewModel = container.Resolve<MaintainRouteViewModel>();
this.DataContext = maintainRouteViewModel;
}
///This button will navigate to the child view.
private void AddRoute_Click(object sender, RoutedEventArgs e)
{
pageAnimationControl.ShowPage(new AddNewRouteView());
}
}
Its ViewModel..
public class MaintainRouteViewModel : viewModelbase
{
private string _statusSuccessMessage = null;
private string _statusFailMessage =null;
private ObservableCollection<RouteDetailsModel> _routeDetailsCollection;
public ObservableCollection<RouteDetailsModel> routeDetailsCollection
{
get
{
return this._routeDetailsCollection;
}
set
{
this._routeDetailsCollection = value;
RaisePropertyChanged("routeDetailsCollection");
}
}
public string StatusSuccessMessage
{
get
{
return _statusSuccessMessage;
}
set
{
_statusSuccessMessage = value;
this.RaisePropertyChanged("StatusSuccessMessage");
}
}
public string StatusFailMessage
{
get { return _statusFailMessage; }
set
{
_statusFailMessage = value;
this.RaisePropertyChanged("StatusFailMessage");
}
}
public MaintainRouteViewModel()
{
///it will load some data to the Observablecollection
getAllCurrentRouteData();
}
}
Now Below is my Child View and its ViewModel....
public partial class AddNewRouteView : UserControl
{
public AddNewRouteView()
{
InitializeComponent();
IUnityContainer container = UnityResolver.UnityContainerInitiation;
this.DataContext = container.Resolve<AddNewRouteViewModel>();
}
}
Its ViewModel....
public class AddNewRouteViewModel : viewModelbase
{
private MaintainRouteViewModel maintainRouteViewModel;
public ICommand SaveCommand
{
get;
set;
}
[InjectionConstructor]
public AddNewRouteViewModel(MaintainRouteViewModel maintainRouteViewModel)
{
this.maintainRouteViewModel = maintainRouteViewModel;
SaveCommand = new DelegateCommand<object>((a) => ValidateNewRoute());
}
private void ValidateNewRoute()
{
bool flag = saveAndValidate();
if(flag)
{
updateRouteStatus();
}
}
public void updateRouteStatus()
{
maintainRouteViewModel.StatusSuccessMessage = "New Route successfully Added..";
}
}
}
Can Anyone Tell me how to use this way to get the same object of MaintainRouteViewModel in my Child VM Constructor So that i will show the Updated Status Message in my Base view MaintainRouteView???
*It will Work Fine If i replace my MaintainRouteView with below code :
this Is an another approach to use IOC .i previously using this in my project. it Works Fine for me but now i want to implement the same thing using Unity Container. Please Help.
public partial class MaintainRouteView : UserControl
{
public MaintainRouteViewModel maintainRouteViewModel = null;
public MaintainRouteView()
{
InitializeComponent();
maintainRouteViewModel = new MaintainRouteViewModel();
this.DataContext = maintainRouteViewModel;
}
private void AddRoute_Click(object sender, RoutedEventArgs e)
{
pageTransitionControl.ShowPage(
new AddNewRouteView
{
DataContext = new AddNewRouteViewModel(maintainRouteViewModel)
});
}
}
I am able to solve this issue using the LifeTime Management of Unity Container Register Types.
it will work fine if i tell the container to create a singleton instance of the MaintainRouteViewModel Class.
using :
container.RegisterType<MaintainRouteViewModel>(
new ContainerControlledLifetimeManager());
But it's just a workaround to get the expected result. i want to achieve it using a proper dependency injection without any singleton instance principle. Can anyone please help to provide the solution.

Bind to TreeView

I'm trying to bind a class with a dictionary to a treeview. The base class of the objects to bind is ElementT:
// Base.cs in Base.dll
public class ElementT {
protected ElementT mParent;
private string mKey;
protected Dictionary<string, ElementT> mMembers;
//...
public ElementT(string nodeKey) { mKey = nodeKey; }
//...
public ElementT Parent {
get {return mParent}
protected set { mParent = value; }
}
public string Key => mKey;
public Dictionary<string, ElementT> Members => mMembers;
//...
}
public class NamespaceT : ElementT {
public NamespaceT(string key) : base(key) {}
}
Referenced to this base class is EngineT:
// Engine.cs in Engine.dll (References base.dll)
public sealed class EngineT {
private NamespaceT mRoot;
public EngineT() {
mRoot = RootNamespaceT.GetInstance(null);
//...
}
public ElementT RootElement => mRoot;
}
internal class RootNamespaceT : NamespaceT {
//...
private RootNamespaceT() : base("Root") { }
//...
}
In the wpf window class referencing Engine.dll:
// MainWindow.xaml.cs (references Engine.dll)
public partial class MainWindow : Window {
private EngineT mEngine;
private ObservableCollection<ElementT> mElementList;
public MainWindow() {
mEngine = new EngineT();
mElementList = new ObservableCollection<ElementT>();
mElementList.Add(mEngine.RootElement);
InitializeComponent();
//ElementLibraryTreeView.ItemsSource = elementList; ????
}
}
In the XAML:
<TreeView ItemsSource="{Binding Source={StaticResource local:mElementList}}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type Key}" ItemsSource="{Binding Path=Members}">
<TextBlock Text="{Binding Path=Key}"/>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
My goal is to list the Key (mKey) with members of the dictionary Members (mMembers) as children to n levels. In addition, I need to be able to alter the tree display based upon the derived class type such as Namespace. There are many different types that derive from ElementT. My immediate problem is binding the root instance of ElementT to the treeview in code. I'd appreciate any help I can get to point me in the right direction. Thank you.

A PropertyGrid Issue

Please consider my codes below:
I'm getting an error Constructor on type 'System.String' not found. when I add new string to the collection using the PropertyGrid control.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
propertyGrid1.SelectedObject = Class1.Instance.StringCollection;
}
}
-----------------------------------------------------------------------------
public sealed class Class1
{
private static Class1 _instance = new Class1();
private List<string> _stringListCollection = new List<string>();
public Class1()
{
}
public static Class1 Instance
{
get { return _instance; }
}
public List<string> StringCollection
{
get { return _stringListCollection; }
set { _stringListCollection = value; }
}
}
When you assign List of something to PropertyGrid, it tries to show single row with modify ... button,
where default modify dialog require Item class to have default constructor, which is not right in case of string
You can create class with default constructor and string property in it, and assign a collection of that class instead of string
Or you can use EditorAttribute to override default editor
Hope this helps
Here is a little class that implements CollectionEditor and fixes the problem for a list of strings:
public class CollectionEditorBase : CollectionEditor
{
public CollectionEditorBase(Type type) : base(type) { }
protected override object CreateInstance(Type itemType)
{
//Fixes the "Constructor on type 'System.String' not found." when it is an empty list of strings
if (itemType == typeof(string)) return string.Empty;
else return Activator.CreateInstance(itemType);
}
}
Now just change the editor to be used with you list of strings:
public class MySettings
{
[Editor(typeof(CollectionEditorBase), typeof(System.Drawing.Design.UITypeEditor))]
public List<string> ListOfStrings { get; set; } = new List<string>();
}
And then you us an instance of MySettings in the property grid:
propertyGrid1.SelectedObject = new MySettings();
At the top of your class, you would have to use System.ComponentModel and System.ComponentModel.Design or fully qualifies these names in your code.

Categories