How to Create a UWP Reusable Content Dialog That is MVVM Compliant - c#

I am working on a reusable content dialog UserControl that the user can import into their xaml and only have to be responsible for bindings in their respective ViewModel. My UserControl has DependencyProperties tied to appropriate content, but the Content Dialog event's are not visible (programmatically) to users of the UserControl. Specifically, I am looking for .ShowAsync()., but Intellisense does not see .ShowAsync() as being part of UserControl.
I used the examples here as a pattern, but I don't need to extend the DialogContent class for my purpose (I think?): https://learn.microsoft.com/en-us/uwp/api/Windows.UI.Xaml.Controls.ContentDialog
As an experiment, I tried to make this SO work, but I then realized this was sitting on Template 10 framework and Dependency Injection/IoC (I am doing my app in straight C#): UWP ContentDialog Invocation
Here is my UserControl's code behind:
public partial class UserDefinedDialogView : UserControl
{
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("DialogTitle", typeof(string), typeof(UserDefinedDialogView), null);
public static readonly DependencyProperty DialogContentTextProperty =
DependencyProperty.Register("DialogContent", typeof(string), typeof(UserDefinedDialogView), null);
public static readonly DependencyProperty PrimaryButtonTextProperty =
DependencyProperty.Register("DialogPrimaryButtonText", typeof(string), typeof(UserDefinedDialogView), null);
public static readonly DependencyProperty SecondaryButtonTextProperty =
DependencyProperty.Register("DialogSecondaryButtonText", typeof(string), typeof(UserDefinedDialogView), null);
public static readonly DependencyProperty CloseButtonTextProperty =
DependencyProperty.Register("DialogCloseButtonText", typeof(string), typeof(UserDefinedDialogView), null);
// PropertyWrappers
public string DialogTitle
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public string DialogContent
{
get { return (string)GetValue(DialogContentTextProperty); }
set { SetValue(DialogContentTextProperty, value); }
}
public string DialogPrimaryButtonText
{
get { return (string)GetValue(PrimaryButtonTextProperty); }
set { SetValue(PrimaryButtonTextProperty, value); }
}
public string DialogSecondaryButtonText
{
get { return (string)GetValue(SecondaryButtonTextProperty); }
set { SetValue(SecondaryButtonTextProperty, value); }
}
public string DialogCloseButtonText
{
get { return (string)GetValue(CloseButtonTextProperty); }
set { SetValue(CloseButtonTextProperty, value); }
}
public UserDefinedDialogView()
{
this.InitializeComponent();
}
}
The UserControl's xaml:
<UserControl
x:Class="HHPM_NEXT.Views.Common.UserDefinedDialogView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:HHPM_NEXT.Views.Common"
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">
<ContentDialog x:Name="UserDefinedDialog"
Title="{x:Bind DialogTitle, Mode=TwoWay}"
Content="{x:Bind DialogContent, Mode=TwoWay}"
PrimaryButtonText="{x:Bind DialogPrimaryButtonText, Mode=TwoWay}"
CloseButtonText="{x:Bind DialogCloseButtonText, Mode=TwoWay}"
x:FieldModifier="Public">
</ContentDialog>
</UserControl>
Example Implementation (References to Zeroize are in a ViewModel, but I didn't add it because I didn't want this to get too long):
<views1:UserDefinedDialogView x:Name="ConfimationDialog" DialogTitle="{Binding ZeroizeTitle, Mode=TwoWay}" DialogContent="{Binding ZeroizeContent, Mode=TwoWay}"
DialogPrimaryButtonText="{Binding ZeroizeConfirmButtonText, Mode=TwoWay}" DialogCloseButtonText="{Binding ZeroizeCloseButtonText, Mode=TwoWay}"/>

Related

WPF DataGrid Usercontrol Columns

I'm trying to create a Datagrid with Paging, but I haven't gotten that far.
Right now I have this.
<UserControl x:Class="SampleControls.UserControls.PageFilterGrid"
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:SampleControls.UserControls"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="500"
Name="Ultra">
<Grid>
<DataGrid Name="MyGrid" AutoGenerateColumns="{Binding ElementName=Ultra, Path=AutoGenerateColumns}" ItemsSource="{Binding ElementName=Ultra, Path=MyItemsSource}" />
</Grid>
The Codebehind for that control looks like this:
public partial class PageFilterGrid : UserControl
{
public PageFilterGrid()
{
InitializeComponent();
}
public static readonly DependencyProperty MyItemsSourceProperty = DependencyProperty.Register("MyItemsSource",
typeof(IEnumerable), typeof(PageFilterGrid));
public static readonly DependencyProperty GenerateColumns = DependencyProperty.Register("AutoGenerateColumns",
typeof(bool), typeof(PageFilterGrid), new PropertyMetadata(false));
public static readonly DependencyProperty MyUltraGrid = DependencyProperty.Register("UltraGrid",
typeof(DataGrid), typeof(PageFilterGrid), new PropertyMetadata(new DataGrid()));
public IEnumerable MyItemsSource
{
get
{
return (IEnumerable)GetValue(PageFilterGrid.MyItemsSourceProperty);
}
set
{
SetValue(PageFilterGrid.MyItemsSourceProperty, value);
}
}
public bool AutoGenerateColumns
{
get
{
return (bool)GetValue(PageFilterGrid.GenerateColumns);
}
set
{
SetValue(PageFilterGrid.GenerateColumns, value);
}
}
public DataGrid UltraGrid {
get
{
return (DataGrid)GetValue(PageFilterGrid.MyUltraGrid);
}
set
{
SetValue(PageFilterGrid.MyUltraGrid, value);
}
}
}
My question is, if I dont want to autogenerate columns , how can i specify the columns without adding them in code behind? I want to add them to the grid like you would normally in XAML. Something like this below, but this doesn't work.
I've tried bringing back just the columns and setting that property, but that doesn't seem to work either for the XAML.
<controls:PageFilterGrid x:Name="myultra" AutoGenerateColumns="False" MyItemsSource="{Binding MyCollection}">
<controls:PageFilterGrid.UltraGrid>
<controls:PageFilterGrid.UltraGrid.Columns>
<DataGridTextColumn Header="amount" Binding="{Binding}" />
</controls:PageFilterGrid.UltraGrid.Columns>
</controls:PageFilterGrid.UltraGrid>
</controls:PageFilterGrid>

WPF UserControl: setter not called on binding one property in multiple controls and back

I've got a problem with my WPF UserControl binding one property in multiple controls and back. The setters of the business object will not be called. I searched for hours now and tried serveral things which did not work.
My Code
Can be download here: WpfApplicationUserControlProblem.zip
My Business object has 2 DateTime Values to be bound.
public class BusinessObject
{
private DateTime _value1 = DateTime.Today.AddHours(10);
public DateTime Value1
{
get { return _value1; }
set { _value1 = value; } // will never be called but why??
}
private DateTime _value2 = DateTime.Today.AddDays(1).AddHours(15);
public DateTime Value2
{
get { return _value2; }
set { _value2 = value; } // will never be called but why??
}
}
My Main-Window has 2 user controls to bind the 2 values of my object
<Window x:Class="WpfApplicationUserControlProblem.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:WpfApplicationUserControlProblem"
mc:Ignorable="d"
Title="MainWindow" Height="120.961" Width="274.489">
<Grid>
<local:DateTimeUserControl DateTimeValue="{Binding Value1, UpdateSourceTrigger=PropertyChanged}" Margin="10,10,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="241"/>
<local:DateTimeUserControl DateTimeValue="{Binding Value2, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="10,39,0,0" VerticalAlignment="Top" Width="241"/>
</Grid>
public partial class MainWindow : Window
{
private BusinessObject _businessObject = new BusinessObject();
public MainWindow()
{
InitializeComponent();
DataContext = _businessObject;
}
}
My UserControl DateTimeUserControl has one DependencyProperty "DateTimeValue" for receiving the bound business value from the Main-Window. With the "DateTimeValuePropertyChangedCallback" I redirect the received value into a DateValue for the DatePicker and HourValue for the HourTextBox. Changing the DatePicker or HourTextBox should update the DependencyProperty "DateTimeValue" and therefore also the bounded business object. That was my plan.
<UserControl x:Class="WpfApplicationUserControlProblem.DateTimeUserControl"
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:WpfApplicationUserControlProblem"
x:Name="_this"
mc:Ignorable="d">
<Grid>
<DatePicker SelectedDate="{Binding Path=DateValue, ElementName=_this, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Margin="0,0,61,0"/>
<TextBox Text="{Binding Path=HourValue, ElementName=_this, UpdateSourceTrigger=PropertyChanged}" Height="24" VerticalAlignment="Top" HorizontalAlignment="Right" Width="56"/>
</Grid>
public partial class DateTimeUserControl : UserControl, INotifyPropertyChanged
{
public DateTimeUserControl()
{
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
public static readonly DependencyProperty DateTimeValueProperty = DependencyProperty.Register(nameof(DateTimeValue), typeof(DateTime), typeof(DateTimeUserControl), new PropertyMetadata(DateTimeValuePropertyChangedCallback));
public DateTime DateTimeValue
{
get { return (DateTime)GetValue(DateTimeValueProperty); }
set { SetValue(DateTimeValueProperty, value); }
}
private static void DateTimeValuePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DateTimeUserControl control = d as DateTimeUserControl;
control.FirePropertyChanged(d, new PropertyChangedEventArgs(nameof(DateValue)));
control.FirePropertyChanged(d, new PropertyChangedEventArgs(nameof(HourValue)));
}
private void FirePropertyChanged(object sender, PropertyChangedEventArgs args)
{
PropertyChanged?.Invoke(sender, args);
}
public DateTime DateValue
{
get { return DateTimeValue.Date; }
set { DateTimeValue = value.Date.AddHours(DateTimeValue.Hour); }
}
public string HourValue
{
get { return DateTimeValue.Hour.ToString(); }
set { DateTimeValue = DateTimeValue.Date.AddHours(int.Parse(value)); }
}
}
I don't get it
Everything seems to work fine except that the setter of the business object is not called when the DependencyProperty is updated. But why? I also tried everything with DependencyProperties or MultiBindingConverters. I failed on every try.
Can anybody help?
The DateTimeValue Bindings should be declared as TwoWay, while UpdateSourceTrigger=PropertyChanged is certainly redundant:
<local:DateTimeUserControl DateTimeValue="{Binding Value1, Mode=TwoWay}" .../>
You could also declare your DateTimeValue dependency property to bind two-way by default:
public static readonly DependencyProperty DateTimeValueProperty =
DependencyProperty.Register(
nameof(DateTimeValue),
typeof(DateTime),
typeof(DateTimeUserControl),
new FrameworkPropertyMetadata(
default(DateTime),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
DateTimeValuePropertyChangedCallback));
You may ask why this isn't also necessary on the two "internal" bindings in the UserControl's XAML, but both the DatePicker.SelectedDate and the TextBox.Text property are already registered with BindsTwoWayByDefault.

Add a DependencyProperty to ThreadSeparatedImage class of Meta.Vlc library to follow MVVM model

I'm working on a Video Player application using C# and WPF.
I have to follow a MVVM model for this WPF project.
I want to use the Meta.Vlc library to display severals RTSP stream in a grid.
So, I add a "ThreadSeparatedImage" object in my VideoPlayControl XAML (view part of the model):
VideoPlayerControl.xaml:
<UserControl x:Class="TVSCS_View.VideoDisplay.VideoPlayerControl"
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:ctrl="clr-namespace:TVSCS_View.VideoDisplay"
xmlns:vlc="clr-namespace:Vlc.Wpf;assembly=Vlc.Wpf"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:helpers="clr-namespace:TVSCS_View.Helpers"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300"
x:Name="controlVideoDisplay"
DataContext="{Binding ElementName=controlVideoDisplay}">
<Border BorderBrush="Black"
BorderThickness="1">
<Grid x:Name="videoPlayerGrid"
Margin="5,5,5,5">
<TextBlock x:Name="videoNameText"
HorizontalAlignment="Left"
Margin="10,10,0,0"
Text="{Binding Path=VideoStreamName, Mode=OneWay}"
VerticalAlignment="Top" Width="100"/>
<vlc:ThreadSeparatedImage x:Name="videoSource"
ThreadImageSource={Binding Path=ImgSource}" />
</Grid>
</Border>
</UserControl>
Then, I have to implement a DependencyProperty to follow a MVVM model. So I modified Meta.Vlc "ThreadSeparatedImage.cs" class, adding the following code:
public static readonly DependencyProperty ThreadImageSourceProperty =
DependencyProperty.RegisterAttached("ThreadImageSource",
typeof(ImageSource),
typeof(ThreadSeparatedImage),
new FrameworkPropertyMetadata(null,
new PropertyChangedCallback(ImageSourcePropertyChanged)));
private static void ImageSourcePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
ThreadSeparatedImage threadSeparatedImage = obj as ThreadSeparatedImage;
if (null != threadSeparatedImage)
{
threadSeparatedImage.Source = (ImageSource)args.NewValue;
}
}
public static void SetImageSource(UIElement element, ImageSource imageSource)
{
element.SetValue(ThreadImageSourceProperty, imageSource);
}
public static ImageSource GetImageSource(UIElement element)
{
return (ImageSource)element.GetValue(ThreadImageSourceProperty);
}
Finally, I have a view model associated to my "VideoPlayerControl" XAML, with the following properties and methods:
VideoPlayerViewModel.cs
private ImageSource _imageSource;
public ImageSource ImgSource
{
get { return _imageSource; }
set
{
if (true == SetProperty(ref _imageSource, value))
{
RaisePropertyChanged("ImgSource");
}
}
}
public void AddVLCPlayer(VlcPlayer mediaPlayer)
{
mediaPlayer.Stop();
mediaPlayer.LoadMedia(#"rtsp://10.2.92.110:554/profile5/media.smp");
mediaPlayer.Play();
ImgSource = mediaPlayer.VideoSource;
mediaPlayer.VideoSourceChanged += MediaPlayer_VideoSourceChanged;
}
private void MediaPlayer_VideoSourceChanged(object sender, VideoSourceChangedEventArgs e)
{
ImgSource = e.NewVideoSource;
}
"AddVLCPlayer" method could be called at initialization.
With this code, the video stream is neither displayed or updated.
Any idea? Thanks.
A Binding like
ThreadImageSource="{Binding Path=ImgSource}"
in the XAML of your UserControl requires that the DataContext of the control is an instance of your view model, i.e. class VideoPlayerViewModel.
This is usually achieved somewhere in your MainWindow code, where you might have something like this:
public MainWindow()
{
InitializeComponent();
DataContext = new VideoPlayerViewModel();
}
Then the DataContext is inherited by your UserControl somewhere in the MainWindow's XAML tree.
However, this will only work if the UserControl does not explicitly set its DataContext, as you do here:
<UserControl ... x:Name="controlVideoDisplay"
DataContext="{Binding ElementName=controlVideoDisplay}">
Remove that DataContext assignment. As a general rule, never set the DataContext of a UserControl explictly, regardless of what they tell you in online tutorials and blog posts.
Besides that, you should probably avoid modifying the code of the Vlc ThreadSeparatedImage class, and instead create a derived class with your dependency property:
public class MyThreadSeparatedImage : ThreadSeparatedImage
{
public static readonly DependencyProperty ThreadImageSourceProperty =
DependencyProperty.Register(
"ThreadImageSource",
typeof(ImageSource),
typeof(MyThreadSeparatedImage),
new FrameworkPropertyMetadata(null, ThreadImageSourcePropertyChanged));
private static void ThreadImageSourcePropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
((ThreadSeparatedImage)obj).Source = (ImageSource)args.NewValue;
}
public ImageSource ThreadImageSource
{
get { return (ImageSource)element.GetValue(ThreadImageSourceProperty); }
set { element.SetValue(ThreadImageSourceProperty, imageSource); }
}
}
I use a classic Image control too.
In XAML file (view part):
<Image Source="{Binding Path=VideoImageSource}" />
In my associated view model (VidePlayerViewModel.cs):
private ImageSource _videoImageSource;
public ImageSource VideoImageSource
{
get { return _videoImageSource; }
set
{
if (true == SetProperty(ref _videoImageSource, value))
{
RaisePropertyChanged("VideoImageSource");
}
}
}
public void AddVLCPlayer(string videoStreamPath)
{
//Create MediaPlayer:
VlcMediaPlayer = new VlcPlayer(false);
VlcMediaPlayer.Initialize(Globals.pathLibVlc);
//Start player
VlcMediaPlayer.Stop();
VlcMediaPlayer.LoadMedia(videoStreamPath);
VlcMediaPlayer.Play();
//Link VLC player to image source:
VideoImageSource = VlcMediaPlayer.VideoSource;
VlcMediaPlayer.VideoSourceChanged += MediaPlayer_VideoSourceChanged;
}

Wpf Textbox UpdateSourceTrigger doesn't update the source

I have a simple Window with a TextBox
XAML
<Window x:Class="Configurator.ConfiguratorWindow"
x:Name="ConfigWindow" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<TextBox x:Name="DescriptionTextBox" Text="{Binding Path=Description, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
</Window>
in the code behind
public partial class ConfiguratorWindow : Window
{
public ConfiguratorWindow()
{
InitializeComponent();
}
private static DependencyProperty DescriptionProperty = DependencyProperty.Register("Description", typeof(string), typeof(ConfiguratorWindow), new PropertyMetadata());
public string Description
{
get { return GetValue(DescriptionProperty).ToString(); }
set {
SetValue(DescriptionProperty, value);
_actual_monitor.Description = value;
}
}
}
the graphic is updating right, but when i change the text in the textbox and lose focus it doesn't update the source property.
What is wrong?
DependencyProperties are used for UserControls rather than ViewModel type bindings.
You should
Create a ConfigurationWindowViewModel (Read about MVVM) and implement INotifyPropertyChanged
Create a Property Description that utilizes the INotifyPropertyChanged
Create a new instance of that view model to be set to the DataContext of your ConfigurationWindow.
The getter and setter of the CLR wrapper of a dependency property must not contain any other code than GetValue and SetValue. The reason is explained in the XAML Loading and Dependency Properties article on MSDN.
So remove the _actual_monitor.Description = value; assignment from the setter and add a PropertyChangedCallback to react on property value changes:
public partial class ConfiguratorWindow : Window
{
public ConfiguratorWindow()
{
InitializeComponent();
}
private static DependencyProperty DescriptionProperty = DependencyProperty.Register(
"Description", typeof(string), typeof(ConfiguratorWindow),
new PropertyMetadata(DescriptionPropertyChanged));
public string Description
{
get { return (string)GetValue(DescriptionProperty); }
set { SetValue(DescriptionProperty, value); }
}
private static void DescriptionPropertyChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ConfiguratorWindow obj = d as ConfiguratorWindow;
obj._actual_monitor.Text = (string)e.newValue;
}
}
Try this
<Window x:Class="Configurator.ConfiguratorWindow"
xmlns:myWindow="clr-namespace:YourNamespace"
x:Name="ConfigWindow" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<TextBox x:Name="DescriptionTextBox" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type myWindow}}, Path=Description, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
public partial class ConfiguratorWindow : Window
{
public ConfiguratorWindow()
{
InitializeComponent();
}
private static DependencyProperty DescriptionProperty = DependencyProperty.Register("Description", typeof(string), typeof(ConfiguratorWindow), new PropertyMetadata(null, CallBack);
private static void callback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var foo = d as ConfiguratorWindow ;
all you need to do, you can do here
}
public string Description
{
get { return GetValue(DescriptionProperty).ToString(); }
set { SetValue(DescriptionProperty, value);}
}
}
But it would be much easier to just have a View Model and bind to property there.

Binding to DependencyProperty works only with "MyValue" and not "{Binding PropertyHoldingMyValue}"

I am creating a custom "PageHeaderControl" UserControl, with a header property:
public partial class PageHeaderControl: UserControl
{
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header",
typeof(string), typeof(PageHeaderControl),
new PropertyMetadata(""));
public string Header
{
get { return GetValue(HeaderProperty) as string; }
set { SetValue(HeaderProperty, value); }
}
}
In the XAML for that control, I have:
<sdk:Label Content="{Binding Header,Mode=TwoWay}" />
Now for the problem: When I create the control, binding it only works to do this:
<my:PageHeaderControl Header="This is my page header" />
And it does not work to do this, where PageHeader is the property in my ViewModel holding the header value:
<my:PageHeaderControl Header="{Binding PageHeader,Mode=TwoWay}" />
I thought maybe my properties were messed up, but this also works:
<TextBlock Text="{Binding PageHeader,Mode=TwoWay}" />
Any ideas as to what the problem could be!
Thanks so much!!!
Edit:
In my ViewModel, PageHeader is this:
private string _pageHeader = "This is my page header";
public string PageHeader
{
get
{
return _pageHeader;
}
set
{
_pageHeader = value;
RaisePropertyChanged("PageHeader");
}
}
Edit 2:
When I put a breakpoint inside the "get" for my PageHeader property, it does not get hit AT ALL, unless I add in the TextBlock...
If I understand you correctly you're trying to bind a property of an element within your control's XAML markup to the property of the control itself.
If this is the case, see if the following helps you.
PageHeaderControl.xaml:
<UserControl x:Class="TryElementBinding.PageHeaderControl"
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"
x:Name = "MyControl"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock Text="{Binding Header, ElementName=MyControl}"></TextBlock>
</Grid>
PageHeaderControl.xaml.cs:
public partial class PageHeaderControl : UserControl
{
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(string), typeof(PageHeaderControl), new PropertyMetadata(""));
public string Header
{
get
{
return GetValue(HeaderProperty) as string;
}
set
{
SetValue(HeaderProperty, value);
}
}
public PageHeaderControl()
{
InitializeComponent();
}
}
ViewModel.cs:
public class ViewModel : INotifyPropertyChanged
{
private string _pageHeader = "This is my page header";
public string PageHeader
{
get
{
return _pageHeader;
}
set
{
_pageHeader = value;
PropertyChanged(this, new PropertyChangedEventArgs("PageHeader"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
MainPage.xaml:
<Grid x:Name="LayoutRoot" Background="White">
<my:PageHeaderControl Header="{Binding PageHeader, Mode=TwoWay}"></my:PageHeaderControl>
</Grid>
MainPage.xaml.cs:
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
I'm a little bit confused and I think you missed the syntax of Binding inline expression.
after "{Binding" comes Path to your property. Is "PageHeader" is a path to your property?!
I think you mean this:
<my:PageHeader Header="{Binding PageHeader, Mode=TwoWay}" />
<TextBlock Text="{Binding PageHeader, Mode=TwoWay}" />
The problem is that Binding expression only works when you set the value of property using SetValue method and notify the parent DependencyObject that specific property has changed!
You should use a DependencyProperty to have TwoWay Binding on it, OR implement System.ComponentModel.INotifyPropertyChange interface in your class and notify the Binding object manually by calling PropertyChanged event in the interface.
The definition of PageHeader property should be like this:
public static readonly DependencyProperty PageHeaderProperty = DependencyProperty.Register("PageHeader", typeof(string), typeof(YOUROWNER), new PropertyMetadata(""));
public string PageHeader
{
get { return GetValue(PageHeaderProperty) as string; }
set { SetValue(PageHeaderProperty, value); }
}
Cheers

Categories