Data binidng to an instance of class - c#

I am trying to bind an instance of a class to a ListBox in C#.
In my MainPage.xaml.cs
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (fan == null)
fan = (Fanfou)e.Parameter;
RefreshHomeTimeLine(fan.oauth_token, fan.oauth_token_secret);
}
private async void RefreshHomeTimeLine(string access, string access_secret)
{
string text=await fan.getFanfouApi("http://api.fanfou.com/statuses/home_timeline.json", access, access_secret);
fanfouHomeTL = JsonConvert.DeserializeObject<FanfouHTL>(text);
}
The fanfouHomeTL was good, containing a collection of statuses.
The declaration of that class is:
public class FanfouHTL
{
private ObservableCollection<Status> statuses;
public ObservableCollection<Status> Statuses
{
get
{
return statuses;
}
set
{
statuses = value;
}
}
}
Now I am trying to bind that instance to a ListBox (in a Grid) in MainPage.xaml. I have already created ItemTemplate for that ListBox. It seems that if I put the DataContext of the Grid to FanfouHTL(the class), nothing will be displayed in the ListBox; if I set the DC to fanfouHomeTL (the instance), MainPage will fail on InitializeComponent.
Any hint will be highly appreciated.

Are you initialising the instance? Try making a public property instance of FanfouHTL, setting the data context of the listbox to your control and then binding to the property's collection, like so
public FanfouHTL Foobar {get;private set;}
//...snip...
public MyComponent(){
Foobar = new FanfouHTL();
InitialiseComponent();
}
Then, in your XAML
<UserControl x:Name="MyComponent" DataContext="{Binding RelativePath=Self}">
<!--(can't remember exact syntax here off the top of my head, but run with it)-->
<ListBox ItemSource="{Binding Path=Foobar.Statuses}" />
</UserControl>

Related

Access parent window's Grid from User Control

In my MainWindow VM i open the Views from my UserControls like this.
Usercontrol1 is the name of the View made in Xaml.
In my ViewModel of my MainWindow:
private static Grid _myMainGrid;
public static Grid MyMainGrid
{
get { return _myMainGrid; }
set { _myMainGrid = value; }
}
private void OpenUserControl(UserControl myUS)
{
if (MyMainGrid.Children.Count > 0)
{
MyMainGrid.Children.RemoveAt(0);
}
Grid.SetColumn(myUS, 1);
Grid.SetRow(myUS, 0);
MyMainGrid.Children.Add(myUS);
}
private void FindGrid(object obj)
{
var myGrd = obj as Grid;
if (myGrd != null)
{
MyMainGrid = myGrd;
}
}
The command binding to the Button executes this.
private void ExecuteCMD_OpenUserControl1(object obj)
{
FindGrid(obj);
Usercontrol1 _ucItem = new Usercontrol1();
OpenUserControl(_ucItem);
}
Now i want to open Usercontrol2 replacing Usercontrol1 in MyMainGrid from my MainWindow by pressing a button in Usercontrol1. So i have to access the parent Window.
Tried using this methode but can't get it to work in my case.
Let's say you have two children; it's trivial to generalize this to any number of children. Fortunately you've already got viewmodels and views, so we're most of the way there. It's just a matter of wiring it all together in a way that works well with WPF.
Here's a set of skeletal viewmodels. Main, and two children. MainViewModel creates its two child instances. ChildOneViewModel has a Next button command, bound to a Button in ChildOneView.xaml.
When the user clicks that button, we want to switch the active view to child two. Rather than have dependencies going in all directions, ChildOneViewModel is ignorant of what "next" really means; its parent, MainViewModel, is in charge of that. Everybody knows about his children; you've found that in programming, making a class know about its siblings or its parent creates problems.
So all ChildOneViewModel does is expose an event so MainViewModel knows when the button is clicked, and can take any action it likes when that happens. This is cool because what if we could be going to one of two different "next" pages, depending on what the user did in ChildOne? If we move that responsibility to the parent, everything becomes simpler. Easier to write, easier to reuse in a different context.
#region MainViewModel Class
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
ChildOne = new ChildOneViewModel();
ChildTwo = new ChildTwoViewModel();
ActiveChild = ChildOne;
ChildOne.NextButtonClicked += (s, e) => ActiveChild = ChildTwo;
}
#region ActiveChild Property
private INotifyPropertyChanged _activeChild = default(INotifyPropertyChanged);
public INotifyPropertyChanged ActiveChild
{
get { return _activeChild; }
set
{
if (value != _activeChild)
{
_activeChild = value;
OnPropertyChanged();
}
}
}
#endregion ActiveChild Property
public ChildOneViewModel ChildOne { get; private set; }
public ChildTwoViewModel ChildTwo { get; private set; }
}
#endregion MainViewModel Class
#region ChildOneViewModel Class
public class ChildOneViewModel : ViewModelBase
{
public event EventHandler NextButtonClicked;
// You already know how to implement a command, so I'll skip that.
protected void NextButtonCommandMethod()
{
NextButtonClicked?.Invoke(this, EventArgs.Empty);
}
}
#endregion ChildOneViewModel Class
#region ChildTwoViewModel Class
public class ChildTwoViewModel : ViewModelBase
{
}
#endregion ChildTwoViewModel Class
And here's the XAML that translates all of that into actual UI at runtime:
<Window.Resources>
<!--
These are "implicit datatemplates": They have no x:Key, so they'll be
automatically used to display any content of the specified types.
-->
<DataTemplate DataType="{x:Type local:ChildOneViewModel}">
<local:ChildOneView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ChildTwoViewModel}">
<local:ChildTwoView />
</DataTemplate>
</Window.Resources>
<Grid>
<!-- other stuff -->
<UserControl
Content="{Binding ActiveChild}"
/>
<!-- other stuff -->
You don't need OpenUserControl(), FindGrid(), any of that stuff.
I don't fully understand the structure of your application and there are most probably better ways of doing whatever you are trying to do, but you could get a reference to any open window in your application using the Application.Current.Windows property if that's your main issue:
var mainWindow = Application.Current.Windows.OfType<MainWindow>().FirstOrDefault();
Inside a loaded UserControl, you should also be able to get a reference to the parent window of this UserControl like this:
var mainWindow = Window.GetWindow(this) as MainWindow;

How can I add a new listbox item foreach List<string>

Using the Prism Library I've setup a Model inheriting BindableBase (INotiftyPropertyChanged).
Then In the ViewModel, in the constructor I create a new object of my ReadConnections class which will return a List of connection names from a local XML file.
Then I set the Connections property from the method GetIdNode in the ReadConnections class.
Finally I bind the Listbox ItemSource to the Connections property. When I run the application the Listbox is not populated with any listbox items. I'm not sure if binding ItemSource is correct, I've never bound anything to a listbox before.
Model Class:
public class LoginDialogModel : BindableBase
{
private List<string> _connections;
public List<string> Connections
{
get { return _connections; }
set { _connections = value; }
}
}
ViewModel Class Constructor:
public LoginDialogVM()
{
ReadConnections read = new ReadConnections();
LoginModel.Connections = read.GetIdNodes();
}
XAML:
<ListBox HorizontalAlignment="Left" Height="247" Margin="10,10,0,0"
VerticalAlignment="Top" Width="135" ItemsSource="{Binding LoginModel.Connections}"/>
Your propery (with BindableBase inheriting) should looks like this
public class LoginDialogModel : BindableBase
{
private List<string> _connections;
public List<string> Connections
{
get { return _connections; }
set { SetProperty(ref _connections,value); }
}
}
And as you see, SetProperty method takes care about NotifyProperty

Interact with SelectemItem of Treeview

I have implemented the SelectedItem of a treeview according to the following article: Data binding to SelectedItem in a WPF Treeview
The SelectedItem works perfect and it truly reflects the item selected.
Now I want to interact with the selected item, but I'm not sure how. I can create an instance of the BindableSelectedItemBehavior class, but this is not the instance containing the data I'm looking for. How to access the class instance holding the SelectedItem of the treeview?
This is a highlight of my code:
namespace QuickSlide_2._0
{
public class BindableSelectedItemBehavior : Behavior<TreeView>
{
...
}
public partial class Window1 : Window
{
.....
private void New_subject_Click(object sender, RoutedEventArgs e)
{
// here the code to read the instance of the class BindableSelectedItemBehavior and interact
// with the selectedItem when I click on the button
}
}
}
Maybe I'm looking totally in the wrong direction. Your help would be highly appreciated!
You want to use MVVM so that you can bind the dependency property of your behavior and then you can access the value of the SelectedItem that you made.
public class BindableSelectedItemBehavior : Behavior<TreeView>
{
//Dependency property called SelectedTreeViewItem register it
}
public partial class Window1 : Window
{
public Window1()
{
DataContext = new WindowViewModel();
}
private void New_subject_Click(object sender, RoutedEventArgs e)
{
// here the code to read the instance of the class BindableSelectedItemBehavior and interact
// with the selectedItem when I click on the button
var windowViewModel = DataContext as WindowViewModel;
var selectedItem = windowViewModel.SelectedItem;
}
}
public class WindowViewModel()
{
public object SelectedItem { get; set; } // You want to change object to the type you are expecting
}
and on your View
<TreeView>
<TreeView.Behaviors>
<BindableSelectedItemBehavior SelectedTreeViewItem="{Binding SelectedTreeViewItem,Mode=TwoWay}">
</...>
</...>

When accessing window from view model it is always null

What i want to do is to create property into the model ComboBoxItemChange.cs of type ILoginView that is the interface which LoginWindow.xaml.cs is deriving. Using this property i want to grant access to the elements inside LoginWindow. I red that this is correct way to do it using MVVM pattern.
My problem is that property is always null.
LoginWindow.xaml.cs
public partial class LoginWindow : Window, ILoginView
{
public LoginWindow()
{
InitializeComponent();
this.DataContext = new ComboBoxItemChange();
(this.DataContext as ComboBoxItemChange).LoginWindow = this as ILoginView;
}
public void ChangeInputFieldsByRole(string role)
{
MessageBox.Show(role);
}
}
ComboBoxItemChange.cs
public class ComboBoxItemChange : INotifyPropertyChanged
{
public ILoginView LoginWindow { get; set; }
private void ChangeloginWindowInputFields(string value)
{
if (LoginWindow == null)
return;
LoginWindow.ChangeInputFieldsByRole(value);
}
}
ILoginView.cs
public interface ILoginView
{
void ChangeInputFieldsByRole(string role);
}
As stated in comment:
There are two different instances you are creating:
One in code behind where you set ILoginView to window itself
Second in Grid resources where you haven't set ILoginView.
Remove the instance you declared in XAML and let the bindings resolved from the instance you created in code behind. (DataContext will automatically be inherited for child controls).

INotifyPropertyChanged binding not updating as expected

So here is the problem I'm beating my head against: I have a custom user control that exposes two dependency properties that are bound to my ViewModel. In my ViewModel I have an instance of a class that holds multiple properties that express values that relate to the user control as well as to items that control manipulates. Here's a bit of sample code to explain it visually so here is a simple sample of my control, it's a Slider that is combined with a checkbox that allows the user to lock the slider.
<custom:SliderControl IsLocked="{Binding Path=CustomClass.IsLocked, Mode=TwoWay}" SliderValue="{Binding Path=CustomClass.Value, Mode=TwoWay}" />
IsLocked and SliderValue are dependency properties that effectively manipulate the checkbox and slider that are contained in the custom control. All of the control functions work as intended, except for the bindings to the class I've defined. If I create individual properties, as in one int property and one bool property the bindings work as intended. However I have five sliders, and each slider in my actual code has five properties that tie in to them. I'm trying to eliminate code duplication by creating a class to hold these properties in a reusable object shrinking my 25 properties down to 5 class instances.
My CustomClass inherits ObservableObject and has a bool property and int property named IsLocked and SliderValue respectively. For more visual aids here is what it looks like:
public class CustomClass : ObservableObject
{
public const string SliderValuePropertyName = "SliderValue";
private int _sliderValue= 0;
public int SliderValue
{
get
{
return _sliderValue;
}
set
{
if (_sliderValue== value)
{
return;
}
_sliderValue= value;
RaisePropertyChanged(SliderValuePropertyName );
}
}
public const string IsCheckedPropertyName = "IsChecked";
private bool _isChecked = false;
public bool IsChecked
{
get
{
return _isChecked;
}
set
{
if (_isChecked == value)
{
return;
}
_isChecked = value;
RaisePropertyChanged(IsCheckedPropertyName);
}
}
The ViewModel property is very similar and looks like this, an new instance of the class is created when the ViewModel loads:
public const string SliderOnePropertyName = "SliderOne";
private CustomClass _sliderOne;
public CustomClass SliderOne
{
get
{
return _sliderOne;
}
set
{
if (_sliderOne== value)
{
return;
}
_sliderOne= value;
RaisePropertyChanged(SliderOnePropertyName );
}
}
Why won't the updating of the dependency property that is bound to the property in the class update properly? Is it because you can't properly update the class instance property by itself and instead have to update the entire class instance whenever changes occur? Or do I need to further customize the setter in this ViewModel property? As it sits now changing the slider value or checkbox never hits the bound property at all and nothing errors out when debugging.
EDIT: I've also surrounded the control in a Border and set the Border UIElement's DataContext to that of the class and then subsequently applied the more simple path binding to the underlying custom control. This however did not have any effect on my problem.
I'm a homegrown programmer so I often miss things when putting code together and I'm guessing this is the case here, unless what I'm trying just won't work.
Any help would be greatly appreciated.
EDIT: So I've been toying around with using a custom event that will let me know when the specific property of the custom control changes and then having that event wired up in my ViewModel to update the existing class. This works but still creates code duplication as now I have to have 10 events, 2 events per control, one to check for when the value of the slider changes and the other to detect when the checkbox IsChecked value changes. This code duplication exists since you can't route multiple command parameters (like a simple string identifier for which slider is being manipulated as well as the value you want to use in the code). This limitation means I can't just use 2 events that differentiate between which control is undergoing changes within the defined method as exposing the physical control to the ViewModel breaks the MVVM pattern. Using a class as the datacontext for the user control made it so I didn't care what control was being manipulated as they each had their own class instance. Using events this unravels the MVVM pattern as now I need to know which of the five controls is being manipulated by the user.
It can't be this hard to use a class in property bindings. I have to be missing something remedial.
here is a full example:
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
public class ViewModel
{
public SliderValues slv { get; private set; }
public ViewModel()
{
slv = new SliderValues();
}
}
public class SliderValues : INotifyPropertyChanged
{
bool _isLocked = false;
public bool IsLocked
{
get { return _isLocked; }
set
{
_isLocked = value;
OnPropertyChanged("IsLocked");
}
}
int _theValue = 5;
public int TheValue
{
get { return _theValue; }
set
{
_theValue = value;
OnPropertyChanged("TheValue");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string prop)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
Now the xaml:
<UserControl x:Class="TestBindings.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Slider Height="23" HorizontalAlignment="Left" Margin="114,138,0,0" Name="slider1" VerticalAlignment="Top" Width="100"
DataContext="{Binding slv}" Value="{Binding TheValue, Mode=TwoWay}"/>
</Grid>
</UserControl>
May be there is just a syntactical error. Try this
{Binding Path=CustomClass.IsLocked, Mode=TwoWay}
Try this...<custom:SliderControl DataContext="{Binding CustomClass}" IsLocked="{Binding IsLocked, Mode=TwoWay}" SliderValue="{Binding Value, Mode=TwoWay}" />

Categories