Why isn't my control updating with my static property? - c#

I've gone through some past answers on this and am binding to the static property the same way they prescribe, as far as I can tell. My binding is properly obtaining the value but it's just not updating when that property get's changed. Here is my code:
My class where I define the variable:
public static class Globals
{
private static string file_name;
public static string FILE_NAME
{
get { return file_name; }
set
{
file_name = value;
OnStaticPropertyChanged(nameof(FILE_NAME));
}
}
public static event PropertyChangedEventHandler StaticPropertyChanged;
private static void OnStaticPropertyChanged(string propertyName)
{
StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyName));
}
}
The applicable XAML:
<Page x:Class="CADViewer.Pages.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CADViewer"
xmlns:s="clr-namespace:CADViewer"
mc:Ignorable="d"
d:DesignHeight="{x:Static SystemParameters.PrimaryScreenHeight}" d:DesignWidth="{x:Static SystemParameters.PrimaryScreenWidth}"
Title="MainPage" Background="#282D33">
<Grid>
<Label Content="{Binding Source={x:Static local:Globals.FILE_NAME}, Mode=OneWay}" FontSize="20" Margin="20, 20, 0, 0" HorizontalAlignment="Left"/>
</Grid>
</Page>
Any help would be much appreciated. This is driving me nuts.
I tried via the means shown above. This was according to previous questions on this problem.

Try this binding which includes a path:
<Label Content="{Binding Path=(local:Globals.FILE_NAME), Mode=OneWay}"
FontSize="20" Margin="20, 20, 0, 0" HorizontalAlignment="Left"/>
You can update the Label by setting the static property to a new value:
Globals.FILE_NAME = "new value...";

I changed my binding from:
Content="{Binding Source={x:Static local:Globals.FILE_NAME}, Mode=OneWay}"
to:
Content="{Binding Path=(local:Globals.FILE_NAME), Mode=OneWay}"
and that did it for me.

Related

WPF: Binding UserControl inside ItemsControl

I'm tryin to make some wpf, which displays my user control for every day of some date range. So far ive tryied datagrid, but it does not support different data type of rows, so I'm tryin to solve it by UserControl and ItemsControl.
My UserControl - PeriodDayControl.xaml looks like this:
<UserControl x:Class="WpfApp.PeriodDayControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp"
mc:Ignorable="d" Height="168.443" Width="104.098">
<Grid>
<TextBox Text="{Binding Path=name}" HorizontalAlignment="Left" Height="23" Margin="20,10,21,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="63" TextAlignment="Center"/>
<TextBox Text="{Binding Path=price}" HorizontalAlignment="Left" Height="23" Margin="31,61,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="41" TextAlignment="Center"/>
<CheckBox IsChecked="{Binding Path=check}" Content="CheckBox" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="42,117,0,0" Height="16" Width="16" RenderTransformOrigin="0.372,0.449"/>
</Grid>
</UserControl>
And code to register properties for binding (PeriodDayControl.xaml.cs):
public PeriodDayControl()
{
InitializeComponent();
}
public string name
{
get { return (string)GetValue(nameProperty); }
set { SetValue(nameProperty, value); }
}
public static readonly DependencyProperty nameProperty =
DependencyProperty.Register("name", typeof(string), typeof(PeriodDayControl));
public decimal price
{
get { return (decimal)GetValue(priceProperty); }
set { SetValue(priceProperty, value); }
}
public static readonly DependencyProperty priceProperty =
DependencyProperty.Register("price", typeof(decimal), typeof(PeriodDayControl));
public bool check
{
get { return (bool)GetValue(checkProperty); }
set { SetValue(checkProperty, value); }
}
public static readonly DependencyProperty checkProperty =
DependencyProperty.Register("check", typeof(bool), typeof(PeriodDayControl));
So it look's like this in designer:
In MainWindow.xaml I'm trying to use Items control, to create template:
<ItemsControl x:Name="ItemsControlMain" ItemsSource="{Binding ViewModels}" Margin="0,166,0,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:PeriodDayControl name="{Binding Path=nameProperty}" price="{Binding Path=priceProperty}" check="{Binding Path=checkProperty}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
and here is my try to create and populate data to PeriodDayControl:
List<PeriodDayControl> pdcList = new List<PeriodDayControl>();
pdcList.Add(new PeriodDayControl() { name = "01/01",price =(decimal)55, check=true});
pdcList.Add(new PeriodDayControl() { name = "02/01",price =(decimal)55, check=false});
pdcList.Add(new PeriodDayControl() { name = "03/01",price =(decimal)55, check=true});
ObservableCollection<PeriodDayControl> pdcColl = new ObservableCollection<PeriodDayControl>(pdcList);
ItemsControlMain.ItemsSource = pdcColl;
Here is how it looks now:
And finally here is what I'm trying to achive:
Right now it shows:
And here are my questions. Is it right decision to use ItemsControl? Or are there any other posibilities, to achive such funcionality? What's wrong with this solution(why it does not populate data)? To make context, I would like to change checkbox/price and then press button , which will read data from all of UserControl and save it to db.Thank you for any advice.

Closing an Open Window Using MVVM Pattern, Produces System.NullReferenceException error

I'm trying to learn MVVM pattern using WPF C#. And I'm running into an error when trying to close an opened window after saving information to an sqlite database. When the command to save a new contact is raised, I am getting an error on HasAddedContact(this, new EventArgs());
Error: System.NullReferenceException: 'Object reference not set to an instance of an object.'
My ViewModel:
public class NewContactViewModel : BaseViewModel
{
private ContactViewModel _contact;
public ContactViewModel Contact
{
get { return _contact; }
set { SetValue(ref _contact, value); }
}
public SaveNewContactCommand SaveNewContactCommand { get; set; }
public event EventHandler HasAddedContact;
public NewContactViewModel()
{
SaveNewContactCommand = new SaveNewContactCommand(this);
_contact = new ContactViewModel();
}
public void SaveNewContact()
{
var newContact = new Contact()
{
Name = Contact.Name,
Email = Contact.Email,
Phone = Contact.Phone
};
DatabaseConnection.Insert(newContact);
HasAddedContact(this, new EventArgs());
}
}
SaveNewContactCommand:
public class SaveNewContactCommand : ICommand
{
public NewContactViewModel VM { get; set; }
public SaveNewContactCommand(NewContactViewModel vm)
{
VM = vm;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
VM.SaveNewContact();
}
}
NewContactWindow.Xaml.Cs code behind:
public partial class NewContactWindow : Window
{
NewContactViewModel _viewModel;
public NewContactWindow()
{
InitializeComponent();
_viewModel = new NewContactViewModel();
DataContext = _viewModel;
_viewModel.HasAddedContact += Vm_ContactAdded;
}
private void Vm_ContactAdded(object sender, EventArgs e)
{
this.Close();
}
}
Adding additional code where I call the new window:
public class ContactsViewModel
{
public ObservableCollection<IContact> Contacts { get; set; } = new ObservableCollection<IContact>();
public NewContactCommand NewContactCommand { get; set; }
public ContactsViewModel()
{
NewContactCommand = new NewContactCommand(this);
GetContacts();
}
public void GetContacts()
{
using(var conn = new SQLite.SQLiteConnection(DatabaseConnection.dbFile))
{
conn.CreateTable<Contact>();
var contacts = conn.Table<Contact>().ToList();
Contacts.Clear();
foreach (var contact in contacts)
{
Contacts.Add(contact);
}
}
}
public void CreateNewContact()
{
var newContactWindow = new NewContactWindow();
newContactWindow.ShowDialog();
GetContacts();
}
}
ContactsWindow.Xaml
<Window x:Class="Contacts_App.View.ContactsWindow"
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"
xmlns:local="clr-namespace:Contacts_App.View"
xmlns:vm="clr-namespace:Contacts_App.ViewModel"
mc:Ignorable="d"
Title="Contacts Window" Height="320" Width="400">
<Window.Resources>
<vm:ContactsViewModel x:Key="vm"/>
</Window.Resources>
<StackPanel Margin="10">
<Button
Content="New Contact"
Command="{Binding NewContactCommand}"/>
<TextBox Margin="0,5,0,5"/>
<ListView
Height="200"
Margin="0,5,0,0"
ItemsSource="{Binding Contacts}">
<ListView.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Window>
NewContactWindow.Xaml
<Window x:Class="Contacts_App.View.NewContactWindow"
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"
xmlns:local="clr-namespace:Contacts_App.View"
xmlns:vm="clr-namespace:Contacts_App.ViewModel"
mc:Ignorable="d"
Title="New Contact Window" Height="250" Width="350">
<Window.Resources>
<vm:NewContactViewModel x:Key="vm"/>
</Window.Resources>
<Grid>
<StackPanel
Margin="10">
<Label Content="Name" />
<TextBox
Text="{Binding Source={StaticResource vm}, Path=Contact.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,0,0,5"/>
<Label Content="Email" />
<TextBox
Text="{Binding Source={StaticResource vm}, Path=Contact.Email, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,0,0,5"/>
<Label Content="Phone Number" />
<TextBox
Text="{Binding Source={StaticResource vm}, Path=Contact.Phone, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,0,0,5"/>
<Button
Content="Save"
Command="{Binding Source={StaticResource vm}, Path=SaveNewContactCommand}"/>
</StackPanel>
</Grid>
</Window>
You're creating NewContactWindow's viewmodel in the constructor, correctly assigning it to DataContext, and correctly adding a handler to that event. Unfortunately, you also create a second instance of the same viewmodel in resources, and you manually set the Source property of all the bindings to use the one in the resources, which doesn't have the event handler.
Window.DataContext, which you set in the constructor, is the default Source for any binding in the Window XAML. Just let it do its thing. I also removed all the redundant Mode=TwoWay things from the Bindings to TextBox.Text, since that property is defined so that all bindings on it will be TwoWay by default. I don't think UpdateSourceTrigger=PropertyChanged is doing anything necessary or helpful either: That causes the Binding to update your viewmodel property every time a key is pressed, instead of just when the TextBox loses focus. But I don't think you're doing anything with the properties where that would matter; there's no validation or anything. But TextBox.Text is one of the very few places where that's actually used, so I left it in.
You should remove the analagous viewmodel resource in your other window. It's not doing any harm, but it's useless at best. At worst, it's an attractive nuisance. Kill it with fire and bury the ashes under a lonely crossroads at midnight.
<Window x:Class="Contacts_App.View.NewContactWindow"
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"
xmlns:local="clr-namespace:Contacts_App.View"
xmlns:vm="clr-namespace:Contacts_App.ViewModel"
mc:Ignorable="d"
Title="New Contact Window" Height="250" Width="350">
<Grid>
<StackPanel
Margin="10">
<Label Content="Name" />
<TextBox
Text="{Binding Contact.Name, UpdateSourceTrigger=PropertyChanged}"
Margin="0,0,0,5"/>
<Label Content="Email" />
<TextBox
Text="{Binding Contact.Email, UpdateSourceTrigger=PropertyChanged}"
Margin="0,0,0,5"/>
<Label Content="Phone Number" />
<TextBox
Text="{Binding Contact.Phone, UpdateSourceTrigger=PropertyChanged}"
Margin="0,0,0,5"/>
<Button
Content="Save"
Command="{Binding SaveNewContactCommand}"/>
</StackPanel>
</Grid>
</Window>

Nested UserControl event doesn't work with EventTrigger/InvokeCommandAction in MVVM/WPF scenario

I'm working with WPF with Prism (MVVM), and trying to build an Inspector for a few classes. One of those classes is Vector3:
<Grid x:Name="Vector3Root" Background="White">
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Horizontal">
<xctk:DoubleUpDown Tag="X" Style="{StaticResource DoubleUpDownStyle}" Value="{Binding X}" ValueChanged="Vector3ValueChanged"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<xctk:DoubleUpDown Tag="Y" Style="{StaticResource DoubleUpDownStyle}" Value="{Binding Y}" ValueChanged="Vector3ValueChanged"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<xctk:DoubleUpDown Tag="Z" Style="{StaticResource DoubleUpDownStyle}" Value="{Binding Z}" ValueChanged="Vector3ValueChanged"/>
</StackPanel>
</StackPanel>
</Grid>
And its code-behind
namespace SimROV.WPF.Views{
public partial class Vector3View : UserControl
{
public Vector3View()
{
InitializeComponent();
}
public static readonly RoutedEvent SettingConfirmedEvent =
EventManager.RegisterRoutedEvent("SettingConfirmed", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(Vector3View));
public event RoutedEventHandler SettingConfirmed
{
add { AddHandler(SettingConfirmedEvent, value); }
remove { RemoveHandler(SettingConfirmedEvent, value); }
}
public void Vector3ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
RaiseEvent(new RoutedEventArgs(SettingConfirmedEvent));
}
}}
The problem that I'm struggling with is that I can't catch neither of the fired events (ValueChanged or SettingConfirmed) on another UserControl's ViewModel that is using Vector3View:
<UserControl
x:Class="SimROV.WPF.Views.TransformView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:views="clr-namespace:SimROV.WPF.Views"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:prism="http://prismlibrary.com/"
mc:Ignorable="d" >
<Grid x:Name="TransformRoot" Background="White">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Position" Margin="5"/>
<!--<ContentPresenter ContentTemplate="{StaticResource Vector3Template}"/>-->
<views:Vector3View x:Name="PositionVector3">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SettingConfirmed">
<prism:InvokeCommandAction Command="{Binding PositionValueChangedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</views:Vector3View>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Rotation" Margin="5"/>
<!--<ContentPresenter ContentTemplate="{StaticResource Vector3Template}"/>-->
<views:Vector3View x:Name="RotationVector3" SettingConfirmed="RotationValueChangedEvent"/>
</StackPanel>
</StackPanel>
</Grid>
At this point I CAN catch SettingConfirmed with RotationValueChangedEvent on code-behind, but since I'm following MVVM pattern, that doesn't work for me, which is why I'm using EventTrigger and InvokeCommandAction to catch those events on TransformViewModel, but those never get fired.
Here it's the TransformViewModel:
namespace SimROV.WPF.ViewModels{
public class TransformViewModel : BindableBase
{
private ICommand _positionCommand;
public ICommand PositionValueChangedCommand => this._positionCommand ?? (this._positionCommand = new DelegateCommand(PositionChanged));
private void PositionChanged()
{
}
public TransformViewModel()
{
}
}}
PositionChanged just never gets fired and I can't understand why at all.
I don't know if this is relevant, but Transform is an element of an ObservableCollection<IComponent> at another ViewModel, which is being presented by a ListView with a ItemContainerStyle, that has a ContentPresenter with a ContentTemplateSelector inside.
Can someone point me out on why this is happening and how to fix it?
Thank you.
Your EventTrigger and InvokeCommandAction should work just fine provided that the DataContext of the Vector3View actually is a TransformViewModel so the binding to the PositionValueChangedCommand property succeeds.

WPF binding works only once

I'm developing a C# project in which I've to use WPF and I'm encountering some problems with binding dynamic content to UI.
Briefly, I have this textBlock here declared in a file called NotifyIconResources.xaml:
<TextBlock Name="label_stato" Text="{Binding Source={x:Static Application.Current}, Path=Properties[status]}"/>
It shows the value of a string property, called status, declared in App.xaml.cs:
public partial class App : Application, INotifyPropertyChanged
{
private MainWindow mw;
private TaskbarIcon notifyIcon;
public event PropertyChangedEventHandler PropertyChanged;
private string _status;
private string status
{
get
{
return _status;
}
set
{
_status = value;
NotifyPropertyChanged("status");
}
}
/// <summary>
/// Triggers a GUI update on a property change
/// </summary>
/// <param name="propertyName"></param>
private void NotifyPropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
this.Properties["status"] = "Online";
//create the notifyicon (it's a resource declared in NotifyIconResources.xaml
ResourceDictionary rd = new ResourceDictionary
{
Source = new Uri("/NotifyIconResources.xaml", UriKind.RelativeOrAbsolute)
};
notifyIcon = (TaskbarIcon)rd["NotifyIcon"];
mw = new MainWindow(Environment.GetCommandLineArgs()[1]);
mw.Show();
}
}
The value of the property is dynamic, its initial value is showed in the textBlock, but the next modifications of its value don't result in a refresh of the textBlock content.
NotifyIconResources.xaml is declared in App.xaml:
<Application x:Class="FileSharingOnLAN.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:FileSharingOnLAN"
StartupUri="MainWindow.xaml"
ShutdownMode="OnExplicitShutdown">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="NotifyIconResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
<Application.MainWindow>
<NavigationWindow Source="MainWindow.xaml" Visibility="Visible"></NavigationWindow>
</Application.MainWindow>
The NotifyIconResources.xaml file:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:FileSharingOnLAN"
xmlns:tb="http://www.hardcodet.net/taskbar">
<tb:TaskbarIcon x:Key="NotifyIcon"
IconSource="/Red.ico"
ToolTipText="Click for popup, right-click for menu"
ContextMenu="{StaticResource SysTrayMenu}">
<tb:TaskbarIcon.TrayPopup>
<Border
Background="Black"
Width="200"
Height="100">
<StackPanel>
<Button
Content="{Binding ButtonContent}"
VerticalAlignment="Top"
Command="{Binding ShowImpostazioniWindowCommand}"/>
<Border
Background="Blue"
Width="100"
Height="50"
VerticalAlignment="Bottom"
HorizontalAlignment="Left">
<StackPanel>
<Label
Content="Stato" />
<!--<Button
Content="{Binding Path="status", Source="{x:Static Application.Current}"}"
Command="{Binding StatusClickedCommand}"/>-->
<TextBlock Name="label_stato" Text="{Binding Source={x:Static Application.Current}, Path=Properties[status]}"/>
</StackPanel>
</Border>
</StackPanel>
</Border>
</tb:TaskbarIcon.TrayPopup>
<tb:TaskbarIcon.DataContext>
<local:NotifyIconViewModel />
</tb:TaskbarIcon.DataContext>
</tb:TaskbarIcon>
I've tried to fix it by using OnpropertyChanged, like in this: Binding to change the property but it didn't work.
In the same project I use other binding techniques which work and I know how to solve this problem programmatically but I want to understand where my error is, I'm totally stuck with it.
You have few things that needs to be changed:
First one is status property it self, make it public:
public string Status
{
get
{
return (string)this.Properties["status"];
}
set
{
this.Properties["status"] = value;
NotifyPropertyChanged("Status");
}
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Status = "Online";
...
}
And change your binding to:
<TextBlock Text="{Binding Source={x:Static Application.Current}, Path=Status}" />
Working Example:
<Window x:Class="WpfApplicationTest.MainWindow"
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"
xmlns:local="clr-namespace:WpfApplicationTest"
mc:Ignorable="d"
x:Name="win"
Title="MainWindow" Height="300" Width="300">
<Window.Resources>
</Window.Resources>
<StackPanel FocusManager.FocusedElement="{Binding ElementName=btnDefault}">
<TextBox Text="{Binding Source={x:Static Application.Current}, Path=Status}" />
<TextBlock Text="{Binding Source={x:Static Application.Current}, Path=Status}" />
<Button>Button 7</Button>
</StackPanel>
</Window>
Found a working solution.
I was changing the value of the property in another cs module like this:
Application.Current.Properties["status"] = "Offline";
This line cannot result in a modification of the property, so I wasn't modifying it. So, thanks to https://stackoverflow.com/a/1609155/10173298, I solved it by substituting that line with:
((App)Application.Current).setOffline();
Where setOffline() is a method I've added to App.xaml.cs:
public void setOffline()
{
this.Status = "Offline";
}

Binding DataTemplate Control Property

I have a UserControl like the following:
<UserControl>
<Expander>
<Expander.HeaderTemplate>
<DataTemplate>
<Grid HorizontalAlignment="{Binding Path=HorizontalAlignment, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}, Mode=OneWayToSource}">
<TextBlock Text="{Binding Path=Service, Mode=TwoWay}"/>
</Grid>
</DataTemplate>
</Expander.HeaderTemplate>
</Expander>
</UserControl>
I want to bind the Text property of the TextBlock control to a property of my UserControl class, like for example:
public string Service
{ get; set; }
How can I do?
Try setting the DataContext to the UserControl so you can access the properties
In this situation I have named the UserControl "UI" (Name="UI") so you can bind using ElementName Text="{Binding ElementName=UI, Path=Service}"
Example:
<UserControl x:Class="WpfApplication8.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Name="UI">
<Expander>
<Expander.HeaderTemplate>
<DataTemplate>
<Grid HorizontalAlignment="{Binding Path=HorizontalAlignment, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}, Mode=OneWayToSource}">
<TextBlock Text="{Binding ElementName=UI, Path=Service}" />
</Grid>
</DataTemplate>
</Expander.HeaderTemplate>
</Expander>
</UserControl>
Code:
I have implemented INotifyPropertyChanged this will allow the UI to be updated when Service string changes
public partial class UserControl1 : UserControl, INotifyPropertyChanged
{
public UserControl1()
{
InitializeComponent();
Service = "Test";
}
private string _service;
public string Service
{
get { return _service; }
set { _service = value; NotifyPropertyChanged("Service"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
Result:

Categories