Issue with databinding to class? - c#

I'm having an issue with databinding a textblock to a custom prop inside another class, what am I doing wrong?
mainpage:
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
InitializeLanguage();
}
private void InitializeLanguage()
{
LanguageHelper lh = new LanguageHelper();
// this.TitlePanel.DataContext = lh;
txtTitle.DataContext = lh;
}
}
databinding:
<TextBlock x:Name="txtTitle"
Text="{Binding homepage_subheading}"
Style="{StaticResource PhoneTextNormalStyle}"
Foreground="White"
Margin="12,0"/>
LanguageHelper class:
public class LanguageHelper
{
public String homepage_subheading;
public void changeLanguage()
{
if (true)
{
//english
homepage_subheading = "This is the top / sub Heading";
}
}
}

You don't have a property but a public field, and the databinding engine only works on properties.
So you need to change your class:
public String homepage_subheading { get; set; }
If you want to also notify the UI with your changes of your properties your LanguageHelper should implement the INotifyPropertyChanged interface and fire the PropertyChange event when you modify your properties.

You should declare some dependency property or use INotifyPropertyChanged, I would like to use a dependency property:
public class LanguageHelper : DependencyObject {
public static DependencyProperty Hompage_subheadingProperty =
DependencyProperty.Register("Homepage_subheading", typeof(string), typeof(LanguageHelper));
public String Homepage_subheading {
get { return (string) GetValue(Homepage_subheadingProperty);}
set { SetValue(Homepage_subheadingProperty, value);}
}
}
Note about the naming convention in C#, all properties should have first letter capitalized.

Related

Binding to an object property in ViewModel, or how to use multiple models with the same property names

I am trying to bind to a property of a Model via the ViewModel in an textbox. I created a wrapper in the ViewModel to access the property of the Model. Whenever I put a break point in the get section of this wrapper it triggers, but a break point in the set section is not executed after changing the textbox content. Code is according to the following tutorial: https://www.codeproject.com/Articles/1193164/MVVM-Sample-application-with-a-focus-in-property
The BaseViewModel implements the INPC interface. I am trying to follow the MVVM "rule of thumbs" as close as possible. So no INPC implementation in the model in this case, and the view can only bind to the VM.
What am I doing wrong?
XAML:
<TextBox Grid.Column="1" VerticalAlignment="Center" Text="{Binding Path=ProgramInfo.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Model:
public class ProgramInfo
{
private string _name;
private string _description;
public string Name
{
get => _name;
set
{
_name = value;
}
}
public string Description
{
get => _description;
set
{
_description = value;
}
}
}
ViewModel:
class ProgramInfoViewModel : BaseViewModel
{
private ProgramInfo _programInfo;
public ProgramInfo ProgramInfo
{
get => _programInfo;
set
{
_programInfo = value;
OnPropertyChanged("ProgramInfo");
}
}
}
Code-behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ProgramInfoViewModel();
}
}
_programInfo is always null. you need to create an instance:
class ProgramInfoViewModel : BaseViewModel
{
private ProgramInfo _programInfo = new ProgramInfo();
public ProgramInfo ProgramInfo
{
get => _programInfo;
set
{
_programInfo = value;
OnPropertyChanged("ProgramInfo");
}
}
}
or
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ProgramInfoViewModel { ProgramInfo = new ProgramInfo() };
}
}
a view model wrapper for model property will look like this:
class ProgramInfoViewModel : BaseViewModel
{
private ProgramInfo _programInfo;
private ProgramInfoViewModel(ProgramInfo programInfo)
{
_programInfo = programInfo;
}
public string ProgramInfoName
{
get => _programInfo.Name;
set
{
_programInfo.Name = value;
OnPropertyChanged("ProgramInfoName");
}
}
}
initialization:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var model = new ProgramInfo();
DataContext = new ProgramInfoViewModel(model);
}
}
binding path has to change accordingly:
<TextBox Text="{Binding Path=ProgramInfoName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

How do i use an Object of IValueConverter from DataContext?

The DataContext of my WPF application contains an object of an IVariableConverter, which interacts with the DataContext, and is not static
// Simplified Example
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ViewModel viewModel = new ViewModel();
DataContext = viewModel;
}
}
//I am using Fody PropertyChanged
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
public int someIndex { get; set;}
// The converter that I want to use, which implements the IValueConverter interface
public SomeConverter someConverter { get; set; }
public ViewModel()
{
// ... setting the other variables ...
someConverter = new SomeConverter(this, ...);
}
}
Now I have a TextBlock, which uses a binding to the 'someIndex' variable, which I want to convert using the 'someConverter' from the DataContext (which is an object of 'ViewModel')
My best guess would have been to just use the converters name, like a binding, but that unfortunately didn't help
<TextBlock Text="{binding someIndex, Converter=someConverter}"/>
How do i access the converter?
Thanks for the help!

Why notification for List<T> property doesn't work

Why rising INotifypPropertyChanged for List<T> property doesn't work?
Consider this MCVE:
public class NotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string property = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
public class TextWrapper
{
public string Text { get; set; }
public override string ToString() => Text;
}
public class ViewModel : NotifyPropertyChanged
{
public List<string> List { get; } = new List<string>();
public TextWrapper Text { get; } = new TextWrapper();
public void AddToList(string text)
{
List.Add(text);
OnPropertyChanged(nameof(List));
}
public void ChangeText(string text)
{
Text.Text = text;
OnPropertyChanged(nameof(Text));
}
}
public partial class MainWindow : Window
{
readonly ViewModel _vm = new ViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = _vm;
}
}
xaml:
<TextBlock Text="{Binding Text}" />
<ListBox ItemsSource="{Binding List}" />
Calling _vm.ChangeText(...) will properly update TextBlock, while calling _vm.AddToList(...) doesn't update ListBox (it will stay empty). Why?
Please note: I know about ObservableCollection<T> and I know about two possible workarounds (add setter to List and set it to e.g. null first and then back or change DataContext/ItemsSource). I am just curious what is under roof makes List<T> more special than TextWrapper.
When a WPF Binding handles the PropertyChanged event, it does not update its target property unless the effective value it produces has actually changed.
So unless the List property value actually changes (which it doesn't when you add an element), calling
OnPropertyChanged(nameof(List));
has no effect.
Replace
public List<string> List { get; } = new List<string>();
by
public ObservableCollection<string> List { get; } = new ObservableCollection<string>();
and write the AddToList method like this:
public void AddToList(string text)
{
List.Add(text);
}
For your TextWrapper class: Since you directly bind to the TextWrapper instance, the Binding calls its overridden ToString() method and hence produces a different value whenever the TextWrapper's Text property has changed.

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.

Use DataContext binding to assign a label the value of a public automatic property in another class

In a nutshell, I want to use DataContext binding to assign a label the value of a public automatic property in another class.
So I have a class containing a public automatic property like so:
public class MyData
{
public string DogName { get; set; }
}
My WPF form looks like this:
The CodeBehind for my WPF form is as so:
public partial class MainWindow : Window
{
private MyData myData;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
myData = new MyData();
myData.DogName = "Lulu";
label1.DataContext = myData.DogName;
}
}
This isn't, however, changing the value of label1 to "Lulu", it just stays at "Label". What have I missed out?
Thanks
That is not exactly the common way to work with DataContexts (as you show it, MyData as a class serves no purpose at all).
Try this instead:
//C#
label1.DataContext = new MyData{ DogName = "Lulu" };
//xaml
<Label Content="{Binding Path=DogName}"/>
now, you could for instance also use MyData to contain the label's Width or so.
Another (probably most used) way is to set the parent's DataContext, and make the individual elements use it's properties:
//C#
class MyData
{
public strig DogName{ get; set; }
public strig CatName{ get; set; }
}
this.DataContext = new MyData{ DogName = "Lulu", CatName = "Fifi" };
//xaml
<Label Content="{Binding Path=DogName}"/>
<Label Content="{Binding Path=CatName}"/>

Categories